diff options
Diffstat (limited to 'Source')
379 files changed, 14376 insertions, 10173 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index a4dd918..a0010a2 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 - cmQtAutoGeneratorInitializer.cxx - cmQtAutoGeneratorInitializer.h - cmQtAutoGenerators.cxx - cmQtAutoGenerators.h + cmQtAutoGenerator.cxx + cmQtAutoGenerator.h + cmQtAutoGenInitializer.cxx + cmQtAutoGenInitializer.h + cmQtAutoGeneratorMocUic.cxx + cmQtAutoGeneratorMocUic.h + cmQtAutoGeneratorRcc.cxx + cmQtAutoGeneratorRcc.h cmRST.cxx cmRST.h cmScriptGenerator.h @@ -322,6 +327,7 @@ set(SRCS cmSourceFile.h cmSourceFileLocation.cxx cmSourceFileLocation.h + cmSourceFileLocationKind.h cmSourceGroup.cxx cmSourceGroup.h cmState.cxx @@ -343,6 +349,9 @@ set(SRCS cmTestGenerator.cxx cmTestGenerator.h cmUuid.cxx + cmUVHandlePtr.cxx + cmUVHandlePtr.h + cmUVSignalHackRAII.h cmVariableWatch.cxx cmVariableWatch.h cmVersion.cxx @@ -593,16 +602,15 @@ set(SRCS cm_utf8.c cm_codecvt.hxx cm_codecvt.cxx + cm_thread.hxx + + cmDuration.h + cmDuration.cxx ) SET_PROPERTY(SOURCE cmProcessOutput.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE}) -# Kdevelop only works on UNIX and not windows -if(UNIX) - set(SRCS ${SRCS} cmGlobalKdevelopGenerator.cxx) -endif() - # Xcode only works on Apple if(APPLE) set(SRCS ${SRCS} @@ -757,6 +765,7 @@ target_link_libraries(CMakeLib cmsys ${CMAKE_LIBUV_LIBRARIES} ${CMAKE_LIBRHASH_LIBRARIES} ${CMake_KWIML_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} ) if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR MATCHES "sparc") @@ -794,7 +803,6 @@ include_directories( # set(CTEST_SRCS cmCTest.cxx CTest/cmProcess.cxx - CTest/cmCTestBatchTestHandler.cxx CTest/cmCTestBuildAndTestHandler.cxx CTest/cmCTestBuildCommand.cxx CTest/cmCTestBuildHandler.cxx @@ -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 c262bdd..50a14da 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 2) -#set(CMake_VERSION_RC 0) +set(CMake_VERSION_MINOR 11) +set(CMake_VERSION_PATCH 0) +set(CMake_VERSION_RC 3) diff --git a/Source/CMakeVersion.rc.in b/Source/CMakeVersion.rc.in new file mode 100644 index 0000000..22b4a36 --- /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_RCVERSION@ +#define VER_FILEVERSION_STR "@CMake_RCVERSION_STR@\0" + +#define VER_PRODUCTVERSION @CMake_RCVERSION@ +#define VER_PRODUCTVERSION_STR "@CMake_RCVERSION_STR@\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/CMakeVersionCompute.cmake b/Source/CMakeVersionCompute.cmake index d9218d7..79264ed 100644 --- a/Source/CMakeVersionCompute.cmake +++ b/Source/CMakeVersionCompute.cmake @@ -27,3 +27,13 @@ endif() if(CMake_VERSION_IS_DIRTY) set(CMake_VERSION ${CMake_VERSION}-dirty) endif() + +# Compute the binary version that appears in the RC file. Version +# components in the RC file are 16-bit integers so we may have to +# split the patch component. +if(CMake_VERSION_PATCH MATCHES "^([0-9]+)([0-9][0-9][0-9][0-9])$") + set(CMake_RCVERSION ${CMake_VERSION_MAJOR},${CMake_VERSION_MINOR},${CMAKE_MATCH_1},${CMAKE_MATCH_2}) +else() + set(CMake_RCVERSION ${CMake_VERSION_MAJOR},${CMake_VERSION_MINOR},${CMake_VERSION_PATCH}) +endif() +set(CMake_RCVERSION_STR ${CMake_VERSION}) diff --git a/Source/CPack/IFW/cmCPackIFWGenerator.cxx b/Source/CPack/IFW/cmCPackIFWGenerator.cxx index 825a888..9f1a15e 100644 --- a/Source/CPack/IFW/cmCPackIFWGenerator.cxx +++ b/Source/CPack/IFW/cmCPackIFWGenerator.cxx @@ -9,6 +9,7 @@ #include "cmCPackIFWPackage.h" #include "cmCPackIFWRepository.h" #include "cmCPackLog.h" // IWYU pragma: keep +#include "cmDuration.h" #include "cmGeneratedFileStream.h" #include "cmSystemTools.h" @@ -61,7 +62,7 @@ int cmCPackIFWGenerator::PackageFiles() } } else { cmCPackIFWLogger(WARNING, "The \"CPACK_IFW_REPOSITORIES_DIRECTORIES\" " - << "variable is set, but content will be skiped, " + << "variable is set, but content will be skipped, " << "because this feature available only since " << "QtIFW 3.1. Please update your QtIFW instance." << std::endl); @@ -84,9 +85,9 @@ int cmCPackIFWGenerator::PackageFiles() std::string output; int retVal = 1; cmCPackIFWLogger(OUTPUT, "- Generate repository" << std::endl); - bool res = cmSystemTools::RunSingleCommand(ifwCmd.c_str(), &output, - &output, &retVal, nullptr, - this->GeneratorVerbose, 0); + bool res = cmSystemTools::RunSingleCommand( + ifwCmd.c_str(), &output, &output, &retVal, nullptr, + this->GeneratorVerbose, cmDuration::zero()); if (!res || retVal) { cmGeneratedFileStream ofs(ifwTmpFile.c_str()); ofs << "# Run command: " << ifwCmd << std::endl @@ -194,9 +195,9 @@ int cmCPackIFWGenerator::PackageFiles() std::string output; int retVal = 1; cmCPackIFWLogger(OUTPUT, "- Generate package" << std::endl); - bool res = cmSystemTools::RunSingleCommand(ifwCmd.c_str(), &output, - &output, &retVal, nullptr, - this->GeneratorVerbose, 0); + bool res = cmSystemTools::RunSingleCommand( + ifwCmd.c_str(), &output, &output, &retVal, nullptr, + this->GeneratorVerbose, cmDuration::zero()); if (!res || retVal) { cmGeneratedFileStream ofs(ifwTmpFile.c_str()); ofs << "# Run command: " << ifwCmd << std::endl diff --git a/Source/CPack/IFW/cmCPackIFWInstaller.cxx b/Source/CPack/IFW/cmCPackIFWInstaller.cxx index 422f5d5..05a852d 100644 --- a/Source/CPack/IFW/cmCPackIFWInstaller.cxx +++ b/Source/CPack/IFW/cmCPackIFWInstaller.cxx @@ -93,6 +93,15 @@ void cmCPackIFWInstaller::ConfigureFromOptions() } } + // RemoveTargetDir + if (this->IsSetToOff("CPACK_IFW_PACKAGE_REMOVE_TARGET_DIR")) { + this->RemoveTargetDir = "false"; + } else if (this->IsOn("CPACK_IFW_PACKAGE_REMOVE_TARGET_DIR")) { + this->RemoveTargetDir = "true"; + } else { + this->RemoveTargetDir.clear(); + } + // Logo if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_LOGO")) { if (cmSystemTools::FileExists(option)) { @@ -422,6 +431,10 @@ void cmCPackIFWInstaller::GenerateInstallerFile() xout.Element("MaintenanceToolIniFile", this->MaintenanceToolIniFile); } + if (!this->RemoveTargetDir.empty()) { + xout.Element("RemoveTargetDir", this->RemoveTargetDir); + } + // Different allows if (this->IsVersionLess("2.0")) { // CPack IFW default policy @@ -454,7 +467,7 @@ void cmCPackIFWInstaller::GenerateInstallerFile() std::string name = cmSystemTools::GetFilenameName(this->Resources[i]); std::string path = this->Directory + "/resources/" + name; cmsys::SystemTools::CopyFileIfDifferent(this->Resources[i], path); - resources.push_back(name); + resources.push_back(std::move(name)); } else { cmCPackIFWLogger(WARNING, "Can't copy resources from \"" << this->Resources[i] diff --git a/Source/CPack/IFW/cmCPackIFWInstaller.h b/Source/CPack/IFW/cmCPackIFWInstaller.h index b635f42..37ad339 100644 --- a/Source/CPack/IFW/cmCPackIFWInstaller.h +++ b/Source/CPack/IFW/cmCPackIFWInstaller.h @@ -99,6 +99,10 @@ public: /// Set to true if the installation path can contain non-ASCII characters std::string AllowNonAsciiCharacters; + /// Set to false if the target directory should not be deleted when + /// uninstalling + std::string RemoveTargetDir; + /// Set to false if the installation path cannot contain space characters std::string AllowSpaceInPath; 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/cmCPackArchiveGenerator.cxx b/Source/CPack/cmCPackArchiveGenerator.cxx index 641be38..9ff547a 100644 --- a/Source/CPack/cmCPackArchiveGenerator.cxx +++ b/Source/CPack/cmCPackArchiveGenerator.cxx @@ -132,7 +132,7 @@ int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup) } } // add the generated package to package file names list - packageFileNames.push_back(packageFileName); + packageFileNames.push_back(std::move(packageFileName)); } // Handle Orphan components (components not belonging to any groups) for (auto& comp : this->Components) { @@ -157,7 +157,7 @@ int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup) addOneComponentToArchive(archive, &(comp.second)); } // add the generated package to package file names list - packageFileNames.push_back(packageFileName); + packageFileNames.push_back(std::move(packageFileName)); } } } @@ -178,7 +178,7 @@ int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup) addOneComponentToArchive(archive, &(comp.second)); } // add the generated package to package file names list - packageFileNames.push_back(packageFileName); + packageFileNames.push_back(std::move(packageFileName)); } } return 1; @@ -188,7 +188,7 @@ int cmCPackArchiveGenerator::PackageComponentsAllInOne() { // reset the package file names packageFileNames.clear(); - packageFileNames.push_back(std::string(toplevel)); + packageFileNames.emplace_back(toplevel); packageFileNames[0] += "/"; if (this->IsSet("CPACK_ARCHIVE_FILE_NAME")) { @@ -239,8 +239,7 @@ int cmCPackArchiveGenerator::PackageFiles() cmWorkingDirectory workdir(toplevel); for (std::string const& file : files) { // Get the relative path to the file - std::string rp = - cmSystemTools::RelativePath(toplevel.c_str(), file.c_str()); + std::string rp = cmSystemTools::RelativePath(toplevel, file); archive.Add(rp, 0, nullptr, false); if (!archive) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem while adding file< " diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx index 7fc3c26..8ec54f8 100644 --- a/Source/CPack/cmCPackDebGenerator.cxx +++ b/Source/CPack/cmCPackDebGenerator.cxx @@ -89,7 +89,7 @@ int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel, packageFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY"); packageFileName += "/"; packageFileName += this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME"); - packageFileNames.push_back(packageFileName); + packageFileNames.push_back(std::move(packageFileName)); return retval; } @@ -206,7 +206,7 @@ int cmCPackDebGenerator::PackageComponentsAllInOne( packageFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY"); packageFileName += "/"; packageFileName += this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME"); - packageFileNames.push_back(packageFileName); + packageFileNames.push_back(std::move(packageFileName)); return retval; } diff --git a/Source/CPack/cmCPackDragNDropGenerator.cxx b/Source/CPack/cmCPackDragNDropGenerator.cxx index 1e1543f..e95b96df 100644 --- a/Source/CPack/cmCPackDragNDropGenerator.cxx +++ b/Source/CPack/cmCPackDragNDropGenerator.cxx @@ -4,6 +4,7 @@ #include "cmCPackGenerator.h" #include "cmCPackLog.h" +#include "cmDuration.h" #include "cmGeneratedFileStream.h" #include "cmSystemTools.h" @@ -242,9 +243,9 @@ bool cmCPackDragNDropGenerator::RunCommand(std::ostringstream& command, { int exit_code = 1; - bool result = cmSystemTools::RunSingleCommand(command.str().c_str(), output, - output, &exit_code, nullptr, - this->GeneratorVerbose, 0); + bool result = cmSystemTools::RunSingleCommand( + command.str().c_str(), output, output, &exit_code, nullptr, + this->GeneratorVerbose, cmDuration::zero()); if (!result || exit_code) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Error executing: " << command.str() @@ -411,6 +412,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 +423,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 +468,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 +723,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..d838b30 100644 --- a/Source/CPack/cmCPackGenerator.cxx +++ b/Source/CPack/cmCPackGenerator.cxx @@ -12,10 +12,13 @@ #include "cmCPackComponentGroup.h" #include "cmCPackLog.h" #include "cmCryptoHash.h" +#include "cmDuration.h" +#include "cmFSPermissions.h" #include "cmGeneratedFileStream.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmStateSnapshot.h" +#include "cmVersion.h" #include "cmWorkingDirectory.h" #include "cmXMLSafe.h" #include "cmake.h" @@ -184,7 +187,7 @@ int cmCPackGenerator::InstallProject() const char* tempInstallDirectory = tempInstallDirectoryStr.c_str(); int res = 1; - if (!cmsys::SystemTools::MakeDirectory(bareTempInstallDirectory.c_str())) { + if (!cmsys::SystemTools::MakeDirectory(bareTempInstallDirectory)) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem creating temporary directory: " << (tempInstallDirectory ? tempInstallDirectory : "(NULL)") @@ -201,6 +204,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 +244,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; } @@ -252,9 +278,9 @@ int cmCPackGenerator::InstallProjectViaInstallCommands( cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << ic << std::endl); std::string output; int retVal = 1; - bool resB = - cmSystemTools::RunSingleCommand(ic.c_str(), &output, &output, &retVal, - nullptr, this->GeneratorVerbose, 0); + bool resB = cmSystemTools::RunSingleCommand( + ic.c_str(), &output, &output, &retVal, nullptr, this->GeneratorVerbose, + cmDuration::zero()); if (!resB || retVal) { std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY"); tmpFile += "/InstallOutput.log"; @@ -274,7 +300,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; @@ -287,7 +314,7 @@ int cmCPackGenerator::InstallProjectViaInstalledDirectories( for (std::string const& ifr : ignoreFilesRegexString) { cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Create ignore files regex for: " << ifr << std::endl); - ignoreFilesRegex.push_back(ifr.c_str()); + ignoreFilesRegex.emplace_back(ifr); } } const char* installDirectories = @@ -347,18 +374,17 @@ int cmCPackGenerator::InstallProjectViaInstalledDirectories( continue; } std::string filePath = tempDir; - filePath += "/" + subdir + "/" + - cmSystemTools::RelativePath(top.c_str(), gf.c_str()); + filePath += "/" + subdir + "/" + cmSystemTools::RelativePath(top, gf); cmCPackLogger(cmCPackLog::LOG_DEBUG, "Copy file: " << inFile << " -> " << filePath << std::endl); /* If the file is a symlink we will have to re-create it */ if (cmSystemTools::FileIsSymlink(inFile)) { std::string targetFile; std::string inFileRelative = - cmSystemTools::RelativePath(top.c_str(), inFile.c_str()); + cmSystemTools::RelativePath(top, inFile); cmSystemTools::ReadSymlink(inFile, targetFile); - symlinkedFiles.push_back( - std::pair<std::string, std::string>(targetFile, inFileRelative)); + symlinkedFiles.emplace_back(std::move(targetFile), + std::move(inFileRelative)); } /* If it is not a symlink then do a plain copy */ else if (!(cmSystemTools::CopyFileIfDifferent(inFile.c_str(), @@ -385,7 +411,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 +491,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"); @@ -573,7 +601,8 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects( int retVal = 1; bool resB = cmSystemTools::RunSingleCommand( buildCommand.c_str(), &output, &output, &retVal, - installDirectory.c_str(), this->GeneratorVerbose, 0); + installDirectory.c_str(), this->GeneratorVerbose, + cmDuration::zero()); if (!resB || retVal) { std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY"); tmpFile += "/PreinstallOutput.log"; @@ -609,6 +638,8 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects( cm.GetCurrentSnapshot().SetDefaultDefinitions(); cm.AddCMakePaths(); cm.SetProgressCallback(cmCPackGeneratorProgress, this); + cm.SetTrace(this->Trace); + cm.SetTraceExpand(this->TraceExpand); cmGlobalGenerator gg(&cm); cmMakefile mf(&gg, cm.GetCurrentSnapshot()); if (!installSubDirectory.empty() && installSubDirectory != "/" && @@ -631,6 +662,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 +728,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 +738,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); @@ -733,9 +771,9 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects( } // Remember the list of files before installation // of the current component (if we are in component install) - const char* InstallPrefix = tempInstallDirectory.c_str(); + std::string const& InstallPrefix = tempInstallDirectory; std::vector<std::string> filesBefore; - std::string findExpr(InstallPrefix); + std::string findExpr = tempInstallDirectory; if (componentInstall) { cmsys::Glob glB; findExpr += "/*"; @@ -790,8 +828,7 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects( std::string localFileName; // Populate the File field of each component for (fit = result.begin(); fit != diff; ++fit) { - localFileName = - cmSystemTools::RelativePath(InstallPrefix, fit->c_str()); + localFileName = cmSystemTools::RelativePath(InstallPrefix, *fit); localFileName = localFileName.substr(localFileName.find_first_not_of('/')); Components[installComponent].Files.push_back(localFileName); @@ -954,10 +991,16 @@ int cmCPackGenerator::DoPackage() */ packageFileNames.push_back(tempPackageFileName ? tempPackageFileName : ""); toplevel = tempDirectory; - if (!this->PackageFiles() || cmSystemTools::GetErrorOccuredFlag()) { - cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem compressing the directory" - << std::endl); - return 0; + { // scope that enables package generators to run internal scripts with + // latest CMake policies enabled + cmMakefile::ScopePushPop pp{ this->MakefileMap }; + this->MakefileMap->SetPolicyVersion(cmVersion::GetCMakeVersion()); + + if (!this->PackageFiles() || cmSystemTools::GetErrorOccuredFlag()) { + cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem compressing the directory" + << std::endl); + return 0; + } } /* Prepare checksum algorithm*/ diff --git a/Source/CPack/cmCPackGenerator.h b/Source/CPack/cmCPackGenerator.h index 4e3a6e0..c22f36b 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; @@ -35,6 +36,16 @@ public: } /** + * Put underlying cmake scripts in trace mode. + */ + void SetTrace(bool val) { this->Trace = val; } + + /** + * Put underlying cmake scripts in expanded trace mode. + */ + void SetTraceExpand(bool val) { this->TraceExpand = val; } + + /** * Returns true if the generator may work on this system. * Rational: * Some CPack generator may run on some host and may not on others @@ -168,9 +179,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 @@ -292,6 +305,8 @@ protected: ComponentPackageMethod componentPackageMethod; cmCPackLog* Logger; + bool Trace; + bool TraceExpand; private: cmMakefile* MakefileMap; 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/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx index ddf104c..3f7164a 100644 --- a/Source/CPack/cmCPackNSISGenerator.cxx +++ b/Source/CPack/cmCPackNSISGenerator.cxx @@ -5,6 +5,7 @@ #include "cmCPackComponentGroup.h" #include "cmCPackGenerator.h" #include "cmCPackLog.h" +#include "cmDuration.h" #include "cmGeneratedFileStream.h" #include "cmSystemTools.h" @@ -61,8 +62,7 @@ int cmCPackNSISGenerator::PackageFiles() std::ostringstream str; for (std::string const& file : files) { std::string outputDir = "$INSTDIR"; - std::string fileN = - cmSystemTools::RelativePath(toplevel.c_str(), file.c_str()); + std::string fileN = cmSystemTools::RelativePath(toplevel, file); if (!this->Components.empty()) { const std::string::size_type pos = fileN.find('/'); @@ -89,8 +89,7 @@ int cmCPackNSISGenerator::PackageFiles() std::ostringstream dstr; for (std::string const& dir : dirs) { std::string componentName; - std::string fileN = - cmSystemTools::RelativePath(toplevel.c_str(), dir.c_str()); + std::string fileN = cmSystemTools::RelativePath(toplevel, dir); if (fileN.empty()) { continue; } @@ -115,7 +114,7 @@ int cmCPackNSISGenerator::PackageFiles() dstr << " RMDir \"" << componentOutputDir << "\\" << fileN << "\"" << std::endl; if (!componentName.empty()) { - this->Components[componentName].Directories.push_back(fileN); + this->Components[componentName].Directories.push_back(std::move(fileN)); } } cmCPackLogger(cmCPackLog::LOG_DEBUG, "Uninstall Dirs: " << dstr.str() @@ -301,9 +300,9 @@ int cmCPackNSISGenerator::PackageFiles() cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << nsisCmd << std::endl); std::string output; int retVal = 1; - bool res = - cmSystemTools::RunSingleCommand(nsisCmd.c_str(), &output, &output, &retVal, - nullptr, this->GeneratorVerbose, 0); + bool res = cmSystemTools::RunSingleCommand( + nsisCmd.c_str(), &output, &output, &retVal, nullptr, + this->GeneratorVerbose, cmDuration::zero()); if (!res || retVal) { cmGeneratedFileStream ofs(tmpFile.c_str()); ofs << "# Run command: " << nsisCmd << std::endl @@ -400,9 +399,9 @@ int cmCPackNSISGenerator::InitializeInternal() << std::endl); std::string output; int retVal = 1; - bool resS = - cmSystemTools::RunSingleCommand(nsisCmd.c_str(), &output, &output, &retVal, - nullptr, this->GeneratorVerbose, 0); + bool resS = cmSystemTools::RunSingleCommand( + nsisCmd.c_str(), &output, &output, &retVal, nullptr, + this->GeneratorVerbose, cmDuration::zero()); cmsys::RegularExpression versionRex("v([0-9]+.[0-9]+)"); cmsys::RegularExpression versionRexCVS("v(.*)\\.cvs"); if (!resS || retVal || @@ -668,8 +667,8 @@ std::string cmCPackNSISGenerator::CreateComponentDescription( uploadDirectory = this->GetOption("CPACK_PACKAGE_DIRECTORY"); uploadDirectory += "/CPackUploads"; } - if (!cmSystemTools::FileExists(uploadDirectory.c_str())) { - if (!cmSystemTools::MakeDirectory(uploadDirectory.c_str())) { + if (!cmSystemTools::FileExists(uploadDirectory)) { + if (!cmSystemTools::MakeDirectory(uploadDirectory)) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Unable to create NSIS upload directory " << uploadDirectory << std::endl); @@ -682,7 +681,7 @@ std::string cmCPackNSISGenerator::CreateComponentDescription( cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- Building downloaded component archive: " << archiveFile << std::endl); - if (cmSystemTools::FileExists(archiveFile.c_str(), true)) { + if (cmSystemTools::FileExists(archiveFile, true)) { if (!cmSystemTools::RemoveFile(archiveFile)) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Unable to remove archive file " << archiveFile << std::endl); @@ -737,9 +736,9 @@ std::string cmCPackNSISGenerator::CreateComponentDescription( zipListFileName.c_str()); std::string output; int retVal = -1; - int res = cmSystemTools::RunSingleCommand(cmd.c_str(), &output, &output, - &retVal, dirName.c_str(), - cmSystemTools::OUTPUT_NONE, 0); + int res = cmSystemTools::RunSingleCommand( + cmd.c_str(), &output, &output, &retVal, dirName.c_str(), + cmSystemTools::OUTPUT_NONE, cmDuration::zero()); if (!res || retVal) { std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY"); tmpFile += "/CompressZip.log"; diff --git a/Source/CPack/cmCPackOSXX11Generator.cxx b/Source/CPack/cmCPackOSXX11Generator.cxx index 8d3c40c..e750de3 100644 --- a/Source/CPack/cmCPackOSXX11Generator.cxx +++ b/Source/CPack/cmCPackOSXX11Generator.cxx @@ -6,6 +6,7 @@ #include "cmCPackGenerator.h" #include "cmCPackLog.h" +#include "cmDuration.h" #include "cmGeneratedFileStream.h" #include "cmSystemTools.h" #include "cm_sys_stat.h" @@ -154,9 +155,9 @@ int cmCPackOSXX11Generator::PackageFiles() int numTries = 10; bool res = false; while (numTries > 0) { - res = cmSystemTools::RunSingleCommand(dmgCmd.str().c_str(), &output, - &output, &retVal, nullptr, - this->GeneratorVerbose, 0); + res = cmSystemTools::RunSingleCommand( + dmgCmd.str().c_str(), &output, &output, &retVal, nullptr, + this->GeneratorVerbose, cmDuration::zero()); if (res && !retVal) { numTries = -1; break; diff --git a/Source/CPack/cmCPackPackageMakerGenerator.cxx b/Source/CPack/cmCPackPackageMakerGenerator.cxx index dbcb022..c515b85 100644 --- a/Source/CPack/cmCPackPackageMakerGenerator.cxx +++ b/Source/CPack/cmCPackPackageMakerGenerator.cxx @@ -13,6 +13,7 @@ #include "cmCPackComponentGroup.h" #include "cmCPackLog.h" +#include "cmDuration.h" #include "cmGeneratedFileStream.h" #include "cmSystemTools.h" #include "cmXMLWriter.h" @@ -295,9 +296,9 @@ int cmCPackPackageMakerGenerator::PackageFiles() int numTries = 10; bool res = false; while (numTries > 0) { - res = cmSystemTools::RunSingleCommand(dmgCmd.str().c_str(), &output, - &output, &retVal, nullptr, - this->GeneratorVerbose, 0); + res = cmSystemTools::RunSingleCommand( + dmgCmd.str().c_str(), &output, &output, &retVal, nullptr, + this->GeneratorVerbose, cmDuration::zero()); if (res && !retVal) { numTries = -1; break; @@ -467,7 +468,8 @@ bool cmCPackPackageMakerGenerator::RunPackageMaker(const char* command, std::string output; int retVal = 1; bool res = cmSystemTools::RunSingleCommand( - command, &output, &output, &retVal, nullptr, this->GeneratorVerbose, 0); + command, &output, &output, &retVal, nullptr, this->GeneratorVerbose, + cmDuration::zero()); cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Done running package maker" << std::endl); if (!res || retVal) { diff --git a/Source/CPack/cmCPackProductBuildGenerator.cxx b/Source/CPack/cmCPackProductBuildGenerator.cxx index 6a6dc82..57cf7ea 100644 --- a/Source/CPack/cmCPackProductBuildGenerator.cxx +++ b/Source/CPack/cmCPackProductBuildGenerator.cxx @@ -8,6 +8,7 @@ #include "cmCPackComponentGroup.h" #include "cmCPackLog.h" +#include "cmDuration.h" #include "cmGeneratedFileStream.h" #include "cmSystemTools.h" @@ -145,9 +146,9 @@ bool cmCPackProductBuildGenerator::RunProductBuild(const std::string& command) cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << command << std::endl); std::string output, error_output; int retVal = 1; - bool res = cmSystemTools::RunSingleCommand(command.c_str(), &output, - &error_output, &retVal, nullptr, - this->GeneratorVerbose, 0); + bool res = cmSystemTools::RunSingleCommand( + command.c_str(), &output, &error_output, &retVal, nullptr, + this->GeneratorVerbose, cmDuration::zero()); cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Done running command" << std::endl); if (!res || retVal) { cmGeneratedFileStream ofs(tmpFile.c_str()); diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx index addb54e..507a10c 100644 --- a/Source/CPack/cpack.cxx +++ b/Source/CPack/cpack.cxx @@ -43,6 +43,8 @@ static const char* cmDocumentationOptions[][2] = { { "-D <var>=<value>", "Set a CPack variable." }, { "--config <config file>", "Specify the config file." }, { "--verbose,-V", "enable verbose output" }, + { "--trace", "Put underlying cmake scripts in trace mode." }, + { "--trace-expand", "Put underlying cmake scripts in expanded trace mode." }, { "--debug", "enable debug output (for CPack developers)" }, { "-P <package name>", "override/define CPACK_PACKAGE_NAME" }, { "-R <package version>", "override/define CPACK_PACKAGE_VERSION" }, @@ -98,6 +100,8 @@ int main(int argc, char const* const* argv) argc = args.argc(); argv = args.argv(); + cmSystemTools::EnableMSVCDebugHook(); + cmSystemTools::InitializeLibUV(); cmSystemTools::FindCMakeResources(argv[0]); cmCPackLog log; @@ -106,8 +110,6 @@ int main(int argc, char const* const* argv) log.SetOutputPrefix("CPack: "); log.SetVerbosePrefix("CPack Verbose: "); - cmSystemTools::EnableMSVCDebugHook(); - if (cmSystemTools::GetCurrentWorkingDirectory().empty()) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "Current working directory cannot be established." @@ -119,6 +121,8 @@ int main(int argc, char const* const* argv) bool help = false; bool helpVersion = false; bool verbose = false; + bool trace = false; + bool traceExpand = false; bool debug = false; std::string helpFull; std::string helpMAN; @@ -154,6 +158,10 @@ int main(int argc, char const* const* argv) arg.AddArgument("--debug", argT::NO_ARGUMENT, &debug, "-V"); arg.AddArgument("--config", argT::SPACE_ARGUMENT, &cpackConfigFile, "CPack configuration file"); + arg.AddArgument("--trace", argT::NO_ARGUMENT, &trace, + "Put underlying cmake scripts in trace mode."); + arg.AddArgument("--trace-expand", argT::NO_ARGUMENT, &traceExpand, + "Put underlying cmake scripts in expanded trace mode."); arg.AddArgument("-C", argT::SPACE_ARGUMENT, &cpackBuildConfig, "CPack build configuration"); arg.AddArgument("-G", argT::SPACE_ARGUMENT, &generator, "CPack generator"); @@ -197,6 +205,14 @@ int main(int argc, char const* const* argv) globalMF.AddDefinition("CMAKE_LEGACY_CYGWIN_WIN32", "0"); #endif + if (trace) { + cminst.SetTrace(true); + } + if (traceExpand) { + cminst.SetTrace(true); + cminst.SetTraceExpand(true); + } + bool cpackConfigFileSpecified = true; if (cpackConfigFile.empty()) { cpackConfigFile = cmSystemTools::GetCurrentWorkingDirectory(); @@ -244,7 +260,7 @@ int main(int argc, char const* const* argv) globalMF.AddDefinition("CPACK_BUILD_CONFIG", cpackBuildConfig.c_str()); } - if (cmSystemTools::FileExists(cpackConfigFile.c_str())) { + if (cmSystemTools::FileExists(cpackConfigFile)) { cpackConfigFile = cmSystemTools::CollapseFullPath(cpackConfigFile); cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE, "Read CPack configuration file: " << cpackConfigFile @@ -340,6 +356,10 @@ int main(int argc, char const* const* argv) << std::endl); parsed = 0; } + + cpackGenerator->SetTrace(trace); + cpackGenerator->SetTraceExpand(traceExpand); + if (parsed && !cpackGenerator->Initialize(gen, mf)) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "Cannot initialize the generator " << gen @@ -412,7 +432,7 @@ int main(int argc, char const* const* argv) cmDocumentationEntry e; e.Name = g.first; e.Brief = g.second; - v.push_back(e); + v.push_back(std::move(e)); } doc.SetSection("Generators", v); diff --git a/Source/CTest/cmCTestBatchTestHandler.cxx b/Source/CTest/cmCTestBatchTestHandler.cxx deleted file mode 100644 index 2eed8be..0000000 --- a/Source/CTest/cmCTestBatchTestHandler.cxx +++ /dev/null @@ -1,123 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmCTestBatchTestHandler.h" - -#include "cmCTest.h" -#include "cmCTestMultiProcessHandler.h" -#include "cmCTestTestHandler.h" -#include "cmProcess.h" -#include "cmSystemTools.h" - -#include <map> -#include <utility> -#include <vector> - -cmCTestBatchTestHandler::~cmCTestBatchTestHandler() -{ -} - -void cmCTestBatchTestHandler::RunTests() -{ - this->WriteBatchScript(); - this->SubmitBatchScript(); -} - -void cmCTestBatchTestHandler::WriteBatchScript() -{ - this->Script = this->CTest->GetBinaryDir() + "/Testing/CTestBatch.txt"; - cmsys::ofstream fout; - fout.open(this->Script.c_str()); - fout << "#!/bin/sh\n"; - - for (auto const& t : this->Tests) { - this->WriteSrunArgs(t.first, fout); - this->WriteTestCommand(t.first, fout); - fout << "\n"; - } - fout.flush(); - fout.close(); -} - -void cmCTestBatchTestHandler::WriteSrunArgs(int test, std::ostream& fout) -{ - cmCTestTestHandler::cmCTestTestProperties* properties = - this->Properties[test]; - - fout << "srun "; - // fout << "--jobid=" << test << " "; - fout << "-J=" << properties->Name << " "; - - // Write dependency information - /*if(!this->Tests[test].empty()) - { - fout << "-P=afterany"; - for(TestSet::iterator i = this->Tests[test].begin(); - i != this->Tests[test].end(); ++i) - { - fout << ":" << *i; - } - fout << " "; - }*/ - if (properties->RunSerial) { - fout << "--exclusive "; - } - if (properties->Processors > 1) { - fout << "-n" << properties->Processors << " "; - } -} - -void cmCTestBatchTestHandler::WriteTestCommand(int test, std::ostream& fout) -{ - std::vector<std::string> args = this->Properties[test]->Args; - std::vector<std::string> processArgs; - std::string command; - - command = this->TestHandler->FindTheExecutable(args[1].c_str()); - command = cmSystemTools::ConvertToOutputPath(command.c_str()); - - // Prepends memcheck args to our command string if this is a memcheck - this->TestHandler->GenerateTestCommand(processArgs, test); - processArgs.push_back(command); - - for (std::string const& arg : processArgs) { - fout << arg << " "; - } - - std::vector<std::string>::iterator i = args.begin(); - ++i; // the test name - ++i; // the executable (command) - if (args.size() > 2) { - fout << "'"; - } - while (i != args.end()) { - fout << "\"" << *i << "\""; // args to the test executable - ++i; - - if (i == args.end() && args.size() > 2) { - fout << "'"; - } - fout << " "; - } - // TODO ZACH build TestResult.FullCommandLine - // this->TestResult.FullCommandLine = this->TestCommand; -} - -void cmCTestBatchTestHandler::SubmitBatchScript() -{ - cmProcess sbatch; - std::vector<std::string> args; - args.push_back(this->Script); - args.push_back("-o"); - args.push_back(this->CTest->GetBinaryDir() + "/Testing/CTestBatch.txt"); - - sbatch.SetCommand("sbatch"); - sbatch.SetCommandArguments(args); - /*if(sbatch.StartProcess()) - { - //success condition - } - else - { - //fail condition - }*/ -} diff --git a/Source/CTest/cmCTestBatchTestHandler.h b/Source/CTest/cmCTestBatchTestHandler.h deleted file mode 100644 index 42f87bd..0000000 --- a/Source/CTest/cmCTestBatchTestHandler.h +++ /dev/null @@ -1,33 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#ifndef cmCTestBatchTestHandler_h -#define cmCTestBatchTestHandler_h - -#include "cmConfigure.h" // IWYU pragma: keep - -#include "cmCTestMultiProcessHandler.h" -#include "cmsys/FStream.hxx" -#include <string> - -/** \class cmCTestBatchTestHandler - * \brief run parallel ctest - * - * cmCTestBatchTestHandler - */ -class cmCTestBatchTestHandler : public cmCTestMultiProcessHandler -{ -public: - ~cmCTestBatchTestHandler() override; - void RunTests() override; - -protected: - void WriteBatchScript(); - void WriteSrunArgs(int test, std::ostream& fout); - void WriteTestCommand(int test, std::ostream& fout); - - void SubmitBatchScript(); - - std::string Script; -}; - -#endif diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx index a0d68a0..2e1ea4c 100644 --- a/Source/CTest/cmCTestBuildAndTestHandler.cxx +++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx @@ -10,6 +10,8 @@ #include "cmake.h" #include "cmsys/Process.h" +#include <chrono> +#include <ratio> #include <stdlib.h> cmCTestBuildAndTestHandler::cmCTestBuildAndTestHandler() @@ -17,7 +19,7 @@ cmCTestBuildAndTestHandler::cmCTestBuildAndTestHandler() this->BuildTwoConfig = false; this->BuildNoClean = false; this->BuildNoCMake = false; - this->Timeout = 0; + this->Timeout = cmDuration::zero(); } void cmCTestBuildAndTestHandler::Initialize() @@ -49,19 +51,13 @@ int cmCTestBuildAndTestHandler::RunCMake(std::string* outstring, args.push_back(cmSystemTools::GetCMakeCommand()); args.push_back(this->SourceDir); if (!this->BuildGenerator.empty()) { - std::string generator = "-G"; - generator += this->BuildGenerator; - args.push_back(generator); + args.push_back("-G" + this->BuildGenerator); } if (!this->BuildGeneratorPlatform.empty()) { - std::string platform = "-A"; - platform += this->BuildGeneratorPlatform; - args.push_back(platform); + args.push_back("-A" + this->BuildGeneratorPlatform); } if (!this->BuildGeneratorToolset.empty()) { - std::string toolset = "-T"; - toolset += this->BuildGeneratorToolset; - args.push_back(toolset); + args.push_back("-T" + this->BuildGeneratorToolset); } const char* config = nullptr; @@ -75,8 +71,7 @@ int cmCTestBuildAndTestHandler::RunCMake(std::string* outstring, #endif if (config) { - std::string btype = "-DCMAKE_BUILD_TYPE:STRING=" + std::string(config); - args.push_back(btype); + args.push_back("-DCMAKE_BUILD_TYPE:STRING=" + std::string(config)); } for (std::string const& opt : this->BuildOptions) { @@ -192,13 +187,13 @@ 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 << std::endl; if (!cmSystemTools::FileIsDirectory(this->BinaryDir)) { - cmSystemTools::MakeDirectory(this->BinaryDir.c_str()); + cmSystemTools::MakeDirectory(this->BinaryDir); } cmWorkingDirectory workdir(this->BinaryDir); @@ -222,10 +217,11 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) this->BuildTargets.push_back(""); } for (std::string const& tar : this->BuildTargets) { - double remainingTime = 0; - if (this->Timeout > 0) { - remainingTime = this->Timeout - cmSystemTools::GetTime() + clock_start; - if (remainingTime <= 0) { + cmDuration remainingTime = std::chrono::seconds(0); + if (this->Timeout > cmDuration::zero()) { + remainingTime = + this->Timeout - (std::chrono::steady_clock::now() - clock_start); + if (remainingTime <= std::chrono::seconds(0)) { if (outstring) { *outstring = "--build-and-test timeout exceeded. "; } @@ -284,7 +280,7 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) cmCTestTestHandler::FindExecutable(this->CTest, this->TestCommand.c_str(), resultingConfig, extraPaths, failed); - if (!cmSystemTools::FileExists(fullPath.c_str())) { + if (!cmSystemTools::FileExists(fullPath)) { out << "Could not find path to executable, perhaps it was not built: " << this->TestCommand << "\n"; out << "tried to find it in these places:\n"; @@ -320,10 +316,11 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) out << "\n"; // how much time is remaining - double remainingTime = 0; - if (this->Timeout > 0) { - remainingTime = this->Timeout - cmSystemTools::GetTime() + clock_start; - if (remainingTime <= 0) { + cmDuration remainingTime = std::chrono::seconds(0); + if (this->Timeout > cmDuration::zero()) { + remainingTime = + this->Timeout - (std::chrono::steady_clock::now() - clock_start); + if (remainingTime <= std::chrono::seconds(0)) { if (outstring) { *outstring = "--build-and-test timeout exceeded. "; } @@ -361,7 +358,7 @@ int cmCTestBuildAndTestHandler::ProcessCommandLineArguments( idx++; this->BinaryDir = allArgs[idx]; // dir must exist before CollapseFullPath is called - cmSystemTools::MakeDirectory(this->BinaryDir.c_str()); + cmSystemTools::MakeDirectory(this->BinaryDir); this->BinaryDir = cmSystemTools::CollapseFullPath(this->BinaryDir); this->SourceDir = cmSystemTools::CollapseFullPath(this->SourceDir); } else { @@ -391,7 +388,7 @@ int cmCTestBuildAndTestHandler::ProcessCommandLineArguments( } if (currentArg.find("--test-timeout", 0) == 0 && idx < allArgs.size() - 1) { idx++; - this->Timeout = atof(allArgs[idx].c_str()); + this->Timeout = cmDuration(atof(allArgs[idx].c_str())); } if (currentArg == "--build-generator" && idx < allArgs.size() - 1) { idx++; diff --git a/Source/CTest/cmCTestBuildAndTestHandler.h b/Source/CTest/cmCTestBuildAndTestHandler.h index f19cb67..5e6d0aa 100644 --- a/Source/CTest/cmCTestBuildAndTestHandler.h +++ b/Source/CTest/cmCTestBuildAndTestHandler.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include "cmCTestGenericHandler.h" +#include "cmDuration.h" #include <sstream> #include <stddef.h> @@ -67,7 +68,7 @@ protected: std::vector<std::string> TestCommandArgs; std::vector<std::string> BuildTargets; bool BuildNoCMake; - double Timeout; + cmDuration Timeout; }; #endif diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx index f4fc769..ce6fbc7 100644 --- a/Source/CTest/cmCTestBuildHandler.cxx +++ b/Source/CTest/cmCTestBuildHandler.cxx @@ -4,6 +4,7 @@ #include "cmAlgorithms.h" #include "cmCTest.h" +#include "cmDuration.h" #include "cmFileTimeComparison.h" #include "cmGeneratedFileStream.h" #include "cmMakefile.h" @@ -17,6 +18,7 @@ #include <set> #include <stdlib.h> #include <string.h> +#include <utility> static const char* cmCTestErrorMatches[] = { "^[Bb]us [Ee]rror", @@ -282,7 +284,7 @@ int cmCTestBuildHandler::ProcessHandler() this->Quiet); // do we have time for this - if (this->CTest->GetRemainingTimeAllowed() < 120) { + if (this->CTest->GetRemainingTimeAllowed() < std::chrono::minutes(2)) { return 0; } @@ -294,7 +296,7 @@ int cmCTestBuildHandler::ProcessHandler() cmCTestWarningErrorFileLine[entry].RegularExpressionString)) { r.FileIndex = cmCTestWarningErrorFileLine[entry].FileIndex; r.LineIndex = cmCTestWarningErrorFileLine[entry].LineIndex; - this->ErrorWarningFileLineRegex.push_back(r); + this->ErrorWarningFileLineRegex.push_back(std::move(r)); } else { cmCTestLog( this->CTest, ERROR_MESSAGE, "Problem Compiling regular expression: " @@ -327,7 +329,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 +408,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 +422,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 +489,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()); } @@ -634,7 +636,7 @@ void cmCTestBuildHandler::GenerateXMLLogScraped(cmXMLWriter& xml) } void cmCTestBuildHandler::GenerateXMLFooter(cmXMLWriter& xml, - double elapsed_build_time) + cmDuration elapsed_build_time) { xml.StartElement("Log"); xml.Attribute("Encoding", "base64"); @@ -642,9 +644,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); } @@ -705,7 +709,7 @@ cmCTestBuildHandler::LaunchHelper::LaunchHelper(cmCTestBuildHandler* handler) if (this->Handler->UseCTestLaunch) { // Enable launcher fragments. - cmSystemTools::MakeDirectory(launchDir.c_str()); + cmSystemTools::MakeDirectory(launchDir); this->WriteLauncherConfig(); std::string launchEnv = "CTEST_LAUNCH_LOGS="; launchEnv += launchDir; @@ -892,7 +896,7 @@ int cmCTestBuildHandler::RunMakeCommand(const char* command, int* retVal, errorwarning.PreContext.clear(); errorwarning.PostContext.clear(); errorwarning.Error = false; - this->ErrorsAndWarnings.push_back(errorwarning); + this->ErrorsAndWarnings.push_back(std::move(errorwarning)); this->TotalWarnings++; } } @@ -915,7 +919,7 @@ int cmCTestBuildHandler::RunMakeCommand(const char* command, int* retVal, errorwarning.PreContext.clear(); errorwarning.PostContext.clear(); errorwarning.Error = true; - this->ErrorsAndWarnings.push_back(errorwarning); + this->ErrorsAndWarnings.push_back(std::move(errorwarning)); this->TotalErrors++; cmCTestLog(this->CTest, ERROR_MESSAGE, "There was an error: " << cmsysProcess_GetErrorString(cp) << std::endl); @@ -1007,7 +1011,7 @@ void cmCTestBuildHandler::ProcessBuffer(const char* data, size_t length, this->PreContext.clear(); // Store report - this->ErrorsAndWarnings.push_back(errorwarning); + this->ErrorsAndWarnings.push_back(std::move(errorwarning)); this->LastErrorOrWarning = this->ErrorsAndWarnings.end() - 1; this->PostContextCount = 0; } else { diff --git a/Source/CTest/cmCTestBuildHandler.h b/Source/CTest/cmCTestBuildHandler.h index 6e71ad6..a9b121b 100644 --- a/Source/CTest/cmCTestBuildHandler.h +++ b/Source/CTest/cmCTestBuildHandler.h @@ -7,8 +7,10 @@ #include "cmCTestGenericHandler.h" +#include "cmDuration.h" #include "cmProcessOutput.h" #include "cmsys/RegularExpression.hxx" +#include <chrono> #include <deque> #include <iosfwd> #include <stddef.h> @@ -86,14 +88,14 @@ 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, cmDuration 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/cmCTestConfigureCommand.cxx b/Source/CTest/cmCTestConfigureCommand.cxx index c44b866..7b5c3bc 100644 --- a/Source/CTest/cmCTestConfigureCommand.cxx +++ b/Source/CTest/cmCTestConfigureCommand.cxx @@ -57,7 +57,7 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler() } const std::string cmakelists_file = source_dir + "/CMakeLists.txt"; - if (!cmSystemTools::FileExists(cmakelists_file.c_str())) { + if (!cmSystemTools::FileExists(cmakelists_file)) { std::ostringstream e; e << "CMakeLists.txt file does not exist [" << cmakelists_file << "]"; this->SetError(e.str()); diff --git a/Source/CTest/cmCTestConfigureHandler.cxx b/Source/CTest/cmCTestConfigureHandler.cxx index 56a038e..821a94a 100644 --- a/Source/CTest/cmCTestConfigureHandler.cxx +++ b/Source/CTest/cmCTestConfigureHandler.cxx @@ -3,10 +3,11 @@ #include "cmCTestConfigureHandler.h" #include "cmCTest.h" +#include "cmDuration.h" #include "cmGeneratedFileStream.h" -#include "cmSystemTools.h" #include "cmXMLWriter.h" +#include <chrono> #include <ostream> #include <string> @@ -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); @@ -64,7 +64,8 @@ int cmCTestConfigureHandler::ProcessHandler() "Configure with command: " << cCommand << std::endl, this->Quiet); res = this->CTest->RunMakeCommand(cCommand.c_str(), output, &retVal, - buildDirectory.c_str(), 0, ofs); + buildDirectory.c_str(), + cmDuration::zero(), ofs); if (ofs) { ofs.close(); @@ -82,12 +83,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..9c66e73 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -3,6 +3,7 @@ #include "cmCTestCoverageHandler.h" #include "cmCTest.h" +#include "cmDuration.h" #include "cmGeneratedFileStream.h" #include "cmParseBlanketJSCoverage.h" #include "cmParseCacheCoverage.h" @@ -21,6 +22,7 @@ #include "cmsys/Process.h" #include "cmsys/RegularExpression.hxx" #include <algorithm> +#include <chrono> #include <iomanip> #include <iterator> #include <sstream> @@ -39,7 +41,7 @@ public: { this->Process = cmsysProcess_New(); this->PipeState = -1; - this->TimeOut = -1; + this->TimeOut = cmDuration(-1); } ~cmCTestRunProcess() { @@ -63,7 +65,7 @@ public: } } void SetWorkingDirectory(const char* dir) { this->WorkingDirectory = dir; } - void SetTimeout(double t) { this->TimeOut = t; } + void SetTimeout(cmDuration t) { this->TimeOut = t; } bool StartProcess() { std::vector<const char*> args; @@ -78,8 +80,8 @@ public: } cmsysProcess_SetOption(this->Process, cmsysProcess_Option_HideWindow, 1); - if (this->TimeOut != -1) { - cmsysProcess_SetTimeout(this->Process, this->TimeOut); + if (this->TimeOut >= cmDuration::zero()) { + cmsysProcess_SetTimeout(this->Process, this->TimeOut.count()); } cmsysProcess_Execute(this->Process); this->PipeState = cmsysProcess_GetState(this->Process); @@ -107,7 +109,7 @@ private: cmsysProcess* Process; std::vector<std::string> CommandLineStrings; std::string WorkingDirectory; - double TimeOut; + cmDuration TimeOut; }; cmCTestCoverageHandler::cmCTestCoverageHandler() @@ -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); } @@ -239,7 +240,7 @@ bool cmCTestCoverageHandler::ShouldIDoCoverage(std::string const& file, // If it is the same as fileDir, then ignore, otherwise check. std::string relPath; if (!checkDir.empty()) { - relPath = cmSystemTools::RelativePath(checkDir.c_str(), fFile.c_str()); + relPath = cmSystemTools::RelativePath(checkDir, fFile); } else { relPath = fFile; } @@ -276,13 +277,12 @@ int cmCTestCoverageHandler::ProcessHandler() this->CTest->ClearSubmitFiles(cmCTest::PartCoverage); int error = 0; // do we have time for this - if (this->CTest->GetRemainingTimeAllowed() < 120) { + if (this->CTest->GetRemainingTimeAllowed() < std::chrono::minutes(2)) { return error; } 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); @@ -449,7 +450,7 @@ int cmCTestCoverageHandler::ProcessHandler() "Process file: " << fullFileName << std::endl, this->Quiet); - if (!cmSystemTools::FileExists(fullFileName.c_str())) { + if (!cmSystemTools::FileExists(fullFileName)) { cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot find file: " << fullFileName << std::endl); continue; @@ -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); @@ -718,7 +718,7 @@ int cmCTestCoverageHandler::HandleCoberturaCoverage( // build the find file string with the directory from above coverageXMLFile += "/coverage.xml"; - if (cmSystemTools::FileExists(coverageXMLFile.c_str())) { + if (cmSystemTools::FileExists(coverageXMLFile)) { // If file exists, parse it cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Parsing Cobertura XML file: " << coverageXMLFile @@ -741,7 +741,7 @@ int cmCTestCoverageHandler::HandleMumpsCoverage( cmParseGTMCoverage cov(*cont, this->CTest); std::string coverageFile = this->CTest->GetBinaryDir() + "/gtm_coverage.mcov"; - if (cmSystemTools::FileExists(coverageFile.c_str())) { + if (cmSystemTools::FileExists(coverageFile)) { cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Parsing Cache Coverage: " << coverageFile << std::endl, this->Quiet); @@ -754,7 +754,7 @@ int cmCTestCoverageHandler::HandleMumpsCoverage( this->Quiet); cmParseCacheCoverage ccov(*cont, this->CTest); coverageFile = this->CTest->GetBinaryDir() + "/cache_coverage.cmcov"; - if (cmSystemTools::FileExists(coverageFile.c_str())) { + if (cmSystemTools::FileExists(coverageFile)) { cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Parsing Cache Coverage: " << coverageFile << std::endl, this->Quiet); @@ -975,7 +975,7 @@ int cmCTestCoverageHandler::HandleGCovCoverage( std::string testingDir = this->CTest->GetBinaryDir() + "/Testing"; std::string tempDir = testingDir + "/CoverageInfo"; - cmSystemTools::MakeDirectory(tempDir.c_str()); + cmSystemTools::MakeDirectory(tempDir); cmWorkingDirectory workdir(tempDir); int gcovStyle = 0; @@ -1024,7 +1024,8 @@ int cmCTestCoverageHandler::HandleGCovCoverage( *cont->OFS << "* Run coverage for: " << fileDir << std::endl; *cont->OFS << " Command: " << command << std::endl; int res = this->CTest->RunCommand(covargs, &output, &errors, &retVal, - tempDir.c_str(), 0 /*this->TimeOut*/); + tempDir.c_str(), + cmDuration::zero() /*this->TimeOut*/); *cont->OFS << " Output: " << output << std::endl; *cont->OFS << " Errors: " << errors << std::endl; @@ -1388,7 +1389,8 @@ int cmCTestCoverageHandler::HandleLCovCoverage( *cont->OFS << "* Run coverage for: " << fileDir << std::endl; *cont->OFS << " Command: " << command << std::endl; int res = this->CTest->RunCommand(covargs, &output, &errors, &retVal, - fileDir.c_str(), 0 /*this->TimeOut*/); + fileDir.c_str(), + cmDuration::zero() /*this->TimeOut*/); *cont->OFS << " Output: " << output << std::endl; *cont->OFS << " Errors: " << errors << std::endl; @@ -1644,7 +1646,7 @@ int cmCTestCoverageHandler::HandleTracePyCoverage( std::string testingDir = this->CTest->GetBinaryDir() + "/Testing"; std::string tempDir = testingDir + "/CoverageInfo"; - cmSystemTools::MakeDirectory(tempDir.c_str()); + cmSystemTools::MakeDirectory(tempDir); int file_count = 0; for (std::string const& file : files) { @@ -1740,11 +1742,11 @@ std::string cmCTestCoverageHandler::FindFile( cmSystemTools::GetFilenameWithoutLastExtension(fileName); // First check in source and binary directory std::string fullName = cont->SourceDir + "/" + fileNameNoE + ".py"; - if (cmSystemTools::FileExists(fullName.c_str())) { + if (cmSystemTools::FileExists(fullName)) { return fullName; } fullName = cont->BinaryDir + "/" + fileNameNoE + ".py"; - if (cmSystemTools::FileExists(fullName.c_str())) { + if (cmSystemTools::FileExists(fullName)) { return fullName; } return ""; @@ -1963,12 +1965,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: @@ -2011,7 +2012,7 @@ int cmCTestCoverageHandler::RunBullseyeSourceSummary( } std::string file = sourceFile; coveredFileNames.insert(file); - if (!cmSystemTools::FileIsFullPath(sourceFile.c_str())) { + if (!cmSystemTools::FileIsFullPath(sourceFile)) { // file will be relative to the binary dir file = cont->BinaryDir; file += "/"; @@ -2089,11 +2090,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/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx index 8cb795e..e85af5e 100644 --- a/Source/CTest/cmCTestGIT.cxx +++ b/Source/CTest/cmCTestGIT.cxx @@ -113,7 +113,7 @@ std::string cmCTestGIT::FindGitDir() // are a Windows application. Run "cygpath" to get Windows path. std::string cygpath_exe = cmSystemTools::GetFilenamePath(git); cygpath_exe += "/cygpath.exe"; - if (cmSystemTools::FileExists(cygpath_exe.c_str())) { + if (cmSystemTools::FileExists(cygpath_exe)) { char const* cygpath[] = { cygpath_exe.c_str(), "-w", git_dir.c_str(), 0 }; OneLineParser cygpath_out(this, "cygpath-out> ", git_dir_line); @@ -249,7 +249,7 @@ bool cmCTestGIT::UpdateImpl() if (this->GetGitVersion() < cmCTestGITVersion(1, 6, 5, 0)) { recursive = nullptr; // No need to require >= 1.6.5 if there are no submodules. - if (cmSystemTools::FileExists((top_dir + "/.gitmodules").c_str())) { + if (cmSystemTools::FileExists(top_dir + "/.gitmodules")) { this->Log << "Git < 1.6.5 cannot update submodules recursively\n"; } } @@ -258,7 +258,7 @@ bool cmCTestGIT::UpdateImpl() if (this->GetGitVersion() < cmCTestGITVersion(1, 8, 1, 0)) { sync_recursive = nullptr; // No need to require >= 1.8.1 if there are no submodules. - if (cmSystemTools::FileExists((top_dir + "/.gitmodules").c_str())) { + if (cmSystemTools::FileExists(top_dir + "/.gitmodules")) { this->Log << "Git < 1.8.1 cannot synchronize submodules recursively\n"; } } @@ -553,15 +553,15 @@ private: void DoHeaderLine() { // Look for header fields that we need. - if (cmHasLiteralPrefix(this->Line.c_str(), "commit ")) { + if (cmHasLiteralPrefix(this->Line, "commit ")) { this->Rev.Rev = this->Line.c_str() + 7; - } else if (cmHasLiteralPrefix(this->Line.c_str(), "author ")) { + } else if (cmHasLiteralPrefix(this->Line, "author ")) { Person author; this->ParsePerson(this->Line.c_str() + 7, author); this->Rev.Author = author.Name; this->Rev.EMail = author.EMail; this->Rev.Date = this->FormatDateTime(author); - } else if (cmHasLiteralPrefix(this->Line.c_str(), "committer ")) { + } else if (cmHasLiteralPrefix(this->Line, "committer ")) { Person committer; this->ParsePerson(this->Line.c_str() + 10, committer); this->Rev.Committer = committer.Name; diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx index a1249f5..30f76a9 100644 --- a/Source/CTest/cmCTestLaunch.cxx +++ b/Source/CTest/cmCTestLaunch.cxx @@ -377,11 +377,10 @@ void cmCTestLaunch::WriteXMLAction(cmXMLWriter& xml) cmSystemTools::ConvertToUnixSlashes(source); // If file is in source tree use its relative location. - if (cmSystemTools::FileIsFullPath(this->SourceDir.c_str()) && - cmSystemTools::FileIsFullPath(source.c_str()) && + if (cmSystemTools::FileIsFullPath(this->SourceDir) && + cmSystemTools::FileIsFullPath(source) && cmSystemTools::IsSubDirectory(source, this->SourceDir)) { - source = - cmSystemTools::RelativePath(this->SourceDir.c_str(), source.c_str()); + source = cmSystemTools::RelativePath(this->SourceDir, source); } xml.Element("SourceFile", source); @@ -564,7 +563,7 @@ void cmCTestLaunch::LoadScrapeRules( std::string line; cmsys::RegularExpression rex; while (cmSystemTools::GetLineFromStream(fin, line)) { - if (rex.compile(line.c_str())) { + if (rex.compile(line)) { regexps.push_back(rex); } } @@ -629,8 +628,7 @@ void cmCTestLaunch::LoadConfig() cmMakefile mf(&gg, cm.GetCurrentSnapshot()); std::string fname = this->LogDir; fname += "CTestLaunchConfig.cmake"; - if (cmSystemTools::FileExists(fname.c_str()) && - mf.ReadListFile(fname.c_str())) { + if (cmSystemTools::FileExists(fname) && mf.ReadListFile(fname.c_str())) { this->SourceDir = mf.GetSafeDefinition("CTEST_SOURCE_DIRECTORY"); cmSystemTools::ConvertToUnixSlashes(this->SourceDir); } diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx index 3efb039..cb1d947 100644 --- a/Source/CTest/cmCTestMemCheckHandler.cxx +++ b/Source/CTest/cmCTestMemCheckHandler.cxx @@ -3,6 +3,7 @@ #include "cmCTestMemCheckHandler.h" #include "cmCTest.h" +#include "cmDuration.h" #include "cmSystemTools.h" #include "cmXMLParser.h" #include "cmXMLWriter.h" @@ -10,9 +11,11 @@ #include "cmsys/FStream.hxx" #include "cmsys/Glob.hxx" #include "cmsys/RegularExpression.hxx" +#include <chrono> #include <iostream> #include <sstream> #include <string.h> +#include <utility> struct CatToErrorType { @@ -160,7 +163,7 @@ void cmCTestMemCheckHandler::GenerateTestCommand( std::string index; std::ostringstream stream; std::string memcheckcommand = - cmSystemTools::ConvertToOutputPath(this->MemoryTester.c_str()); + cmSystemTools::ConvertToOutputPath(this->MemoryTester); stream << test; index = stream.str(); for (std::string arg : this->MemoryTesterDynamicOptions) { @@ -175,7 +178,7 @@ void cmCTestMemCheckHandler::GenerateTestCommand( } // Create a copy of the memory tester environment variable. // This is used for memory testing programs that pass options - // via environment varaibles. + // via environment variables. std::string memTesterEnvironmentVariable = this->MemoryTesterEnvironmentVariable; for (std::string const& arg : this->MemoryTesterOptions) { @@ -408,8 +411,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); @@ -421,7 +426,7 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() this->MemoryTester.clear(); // Setup the command if (cmSystemTools::FileExists( - this->CTest->GetCTestConfiguration("MemoryCheckCommand").c_str())) { + this->CTest->GetCTestConfiguration("MemoryCheckCommand"))) { this->MemoryTester = this->CTest->GetCTestConfiguration("MemoryCheckCommand"); std::string testerName = @@ -438,17 +443,15 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() this->MemoryTesterStyle = cmCTestMemCheckHandler::UNKNOWN; } } else if (cmSystemTools::FileExists( - this->CTest->GetCTestConfiguration("PurifyCommand").c_str())) { + this->CTest->GetCTestConfiguration("PurifyCommand"))) { this->MemoryTester = this->CTest->GetCTestConfiguration("PurifyCommand"); this->MemoryTesterStyle = cmCTestMemCheckHandler::PURIFY; } else if (cmSystemTools::FileExists( - this->CTest->GetCTestConfiguration("ValgrindCommand") - .c_str())) { + this->CTest->GetCTestConfiguration("ValgrindCommand"))) { this->MemoryTester = this->CTest->GetCTestConfiguration("ValgrindCommand"); this->MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND; } else if (cmSystemTools::FileExists( - this->CTest->GetCTestConfiguration("BoundsCheckerCommand") - .c_str())) { + this->CTest->GetCTestConfiguration("BoundsCheckerCommand"))) { this->MemoryTester = this->CTest->GetCTestConfiguration("BoundsCheckerCommand"); this->MemoryTesterStyle = cmCTestMemCheckHandler::BOUNDS_CHECKER; @@ -532,9 +535,8 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() } if (!this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile") .empty()) { - if (!cmSystemTools::FileExists( - this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile") - .c_str())) { + if (!cmSystemTools::FileExists(this->CTest->GetCTestConfiguration( + "MemoryCheckSuppressionFile"))) { cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot find memory checker suppression file: " << this->CTest->GetCTestConfiguration( @@ -542,12 +544,12 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() << std::endl); return false; } - std::string suppressions = "--suppressions=" + - this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile"); - this->MemoryTesterOptions.push_back(suppressions); + this->MemoryTesterOptions.push_back( + "--suppressions=" + + this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile")); } - std::string outputFile = "--log-file=" + this->MemoryTesterOutputFile; - this->MemoryTesterDynamicOptions.push_back(outputFile); + this->MemoryTesterDynamicOptions.push_back("--log-file=" + + this->MemoryTesterOutputFile); break; } case cmCTestMemCheckHandler::PURIFY: { @@ -555,9 +557,8 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() #ifdef _WIN32 if (this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile") .size()) { - if (!cmSystemTools::FileExists( - this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile") - .c_str())) { + if (!cmSystemTools::FileExists(this->CTest->GetCTestConfiguration( + "MemoryCheckSuppressionFile"))) { cmCTestLog( this->CTest, ERROR_MESSAGE, "Cannot find memory checker suppression file: " @@ -585,7 +586,7 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() "/Testing/Temporary/MemoryChecker.??.DPbd"; this->BoundsCheckerDPBDFile = dpbdFile; this->MemoryTesterDynamicOptions.push_back("/B"); - this->MemoryTesterDynamicOptions.push_back(dpbdFile); + this->MemoryTesterDynamicOptions.push_back(std::move(dpbdFile)); this->MemoryTesterDynamicOptions.push_back("/X"); this->MemoryTesterDynamicOptions.push_back(this->MemoryTesterOutputFile); this->MemoryTesterOptions.push_back("/M"); @@ -844,7 +845,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; @@ -917,9 +918,11 @@ bool cmCTestMemCheckHandler::ProcessMemCheckValgrindOutput( break; // stop the copy of output if we are full } } - cmCTestOptionalLog(this->CTest, DEBUG, "End test (elapsed: " - << (cmSystemTools::GetTime() - sttime) << std::endl, - this->Quiet); + cmCTestOptionalLog( + this->CTest, DEBUG, "End test (elapsed: " + << cmDurationTo<unsigned int>(std::chrono::steady_clock::now() - sttime) + << "s)" << std::endl, + this->Quiet); log = ostr.str(); this->DefectCount += defects; return defects == 0; @@ -929,7 +932,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, @@ -960,9 +963,11 @@ bool cmCTestMemCheckHandler::ProcessMemCheckBoundsCheckerOutput( results[err]++; defects++; } - cmCTestOptionalLog(this->CTest, DEBUG, "End test (elapsed: " - << (cmSystemTools::GetTime() - sttime) << std::endl, - this->Quiet); + cmCTestOptionalLog( + this->CTest, DEBUG, "End test (elapsed: " + << cmDurationTo<unsigned int>(std::chrono::steady_clock::now() - sttime) + << "s)" << std::endl, + this->Quiet); if (defects) { // only put the output of Bounds Checker if there were // errors or leaks detected @@ -1084,10 +1089,10 @@ void cmCTestMemCheckHandler::TestOutputFileNames( files = g.GetFiles(); return; } - } else if (!cmSystemTools::FileExists(ofile.c_str())) { + } else if (!cmSystemTools::FileExists(ofile)) { std::string log = "Cannot find memory tester output file: " + ofile; cmCTestLog(this->CTest, ERROR_MESSAGE, log << std::endl); ofile.clear(); } - files.push_back(ofile); + files.push_back(std::move(ofile)); } diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index 6a7bdc0..50c2d86 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -9,10 +9,16 @@ #include "cmSystemTools.h" #include "cmWorkingDirectory.h" +#include "cm_uv.h" + +#include "cmUVSignalHackRAII.h" // IWYU pragma: keep + #include "cmsys/FStream.hxx" #include "cmsys/String.hxx" #include "cmsys/SystemInformation.hxx" + #include <algorithm> +#include <chrono> #include <iomanip> #include <list> #include <math.h> @@ -95,24 +101,32 @@ void cmCTestMultiProcessHandler::RunTests() if (this->HasCycles) { return; } +#ifdef CMAKE_UV_SIGNAL_HACK + cmUVSignalHackRAII hackRAII; +#endif this->TestHandler->SetMaxIndex(this->FindMaxIndex()); + + uv_loop_init(&this->Loop); this->StartNextTests(); - while (!this->Tests.empty()) { - if (this->StopTimePassed) { - return; - } - this->CheckOutput(); - this->StartNextTests(); - } - // let all running tests finish - while (this->CheckOutput()) { - } + uv_run(&this->Loop, UV_RUN_DEFAULT); + uv_loop_close(&this->Loop); + this->MarkFinished(); this->UpdateCostData(); } -void cmCTestMultiProcessHandler::StartTestProcess(int test) +bool cmCTestMultiProcessHandler::StartTestProcess(int test) { + std::chrono::system_clock::time_point stop_time = this->CTest->GetStopTime(); + if (stop_time != std::chrono::system_clock::time_point() && + stop_time <= std::chrono::system_clock::now()) { + cmCTestLog(this->CTest, ERROR_MESSAGE, "The stop time has been passed. " + "Stopping all tests." + << std::endl); + this->StopTimePassed = true; + return false; + } + cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "test " << test << "\n", this->Quiet); this->TestRunningMap[test] = true; // mark the test as running @@ -120,7 +134,7 @@ void cmCTestMultiProcessHandler::StartTestProcess(int test) this->EraseTest(test); this->RunningCount += GetProcessorsUsed(test); - cmCTestRunTest* testRun = new cmCTestRunTest(this->TestHandler); + cmCTestRunTest* testRun = new cmCTestRunTest(*this); if (this->CTest->GetRepeatUntilFail()) { testRun->SetRunUntilFailOn(); testRun->SetNumberOfRuns(this->CTest->GetTestRepeat()); @@ -143,28 +157,11 @@ void cmCTestMultiProcessHandler::StartTestProcess(int test) this->LockResources(test); if (testRun->StartTest(this->Total)) { - this->RunningTests.insert(testRun); - } else if (testRun->IsStopTimePassed()) { - this->StopTimePassed = true; - delete testRun; - return; - } else { - - for (auto& j : this->Tests) { - j.second.erase(test); - } - - this->UnlockResources(test); - this->Completed++; - this->TestFinishMap[test] = true; - this->TestRunningMap[test] = false; - this->RunningCount -= GetProcessorsUsed(test); - testRun->EndTest(this->Completed, this->Total, false); - if (!this->Properties[test]->Disabled) { - this->Failed->push_back(this->Properties[test]->Name); - } - delete testRun; + return true; } + + this->FinishTestProcess(testRun, false); + return false; } void cmCTestMultiProcessHandler::LockResources(int index) @@ -222,8 +219,7 @@ bool cmCTestMultiProcessHandler::StartTest(int test) // if there are no depends left then run this test if (this->Tests[test].empty()) { - this->StartTestProcess(test); - return true; + return this->StartTestProcess(test); } // This test was not able to start because it is waiting // on depends to run @@ -233,6 +229,11 @@ bool cmCTestMultiProcessHandler::StartTest(int test) void cmCTestMultiProcessHandler::StartNextTests() { size_t numToStart = 0; + + if (this->Tests.empty()) { + return; + } + if (this->RunningCount < this->ParallelLevel) { numToStart = this->ParallelLevel - this->RunningCount; } @@ -326,10 +327,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, @@ -353,45 +366,42 @@ void cmCTestMultiProcessHandler::StartNextTests() } } -bool cmCTestMultiProcessHandler::CheckOutput() +void cmCTestMultiProcessHandler::FinishTestProcess(cmCTestRunTest* runner, + bool started) { - // no more output we are done - if (this->RunningTests.empty()) { - return false; - } - std::vector<cmCTestRunTest*> finished; - std::string out, err; - for (cmCTestRunTest* p : this->RunningTests) { - if (!p->CheckOutput()) { - finished.push_back(p); - } - } - for (cmCTestRunTest* p : finished) { - this->Completed++; - int test = p->GetIndex(); + this->Completed++; + + int test = runner->GetIndex(); + auto properties = runner->GetTestProperties(); - bool testResult = p->EndTest(this->Completed, this->Total, true); - if (p->StartAgain()) { + bool testResult = runner->EndTest(this->Completed, this->Total, started); + if (started) { + if (runner->StartAgain()) { this->Completed--; // remove the completed test because run again - continue; - } - if (testResult) { - this->Passed->push_back(p->GetTestProperties()->Name); - } else { - this->Failed->push_back(p->GetTestProperties()->Name); - } - for (auto& t : this->Tests) { - t.second.erase(test); + return; } - this->TestFinishMap[test] = true; - this->TestRunningMap[test] = false; - this->RunningTests.erase(p); - this->WriteCheckpoint(test); - this->UnlockResources(test); - this->RunningCount -= GetProcessorsUsed(test); - delete p; } - return true; + + if (testResult) { + this->Passed->push_back(properties->Name); + } else if (!properties->Disabled) { + this->Failed->push_back(properties->Name); + } + + for (auto& t : this->Tests) { + t.second.erase(test); + } + + this->TestFinishMap[test] = true; + this->TestRunningMap[test] = false; + this->WriteCheckpoint(test); + this->UnlockResources(test); + this->RunningCount -= GetProcessorsUsed(test); + + delete runner; + if (started) { + this->StartNextTests(); + } } void cmCTestMultiProcessHandler::UpdateCostData() @@ -403,7 +413,7 @@ void cmCTestMultiProcessHandler::UpdateCostData() PropertiesMap temp = this->Properties; - if (cmSystemTools::FileExists(fname.c_str())) { + if (cmSystemTools::FileExists(fname)) { cmsys::ifstream fin; fin.open(fname.c_str()); @@ -456,7 +466,7 @@ void cmCTestMultiProcessHandler::ReadCostData() { std::string fname = this->CTest->GetCostDataFile(); - if (cmSystemTools::FileExists(fname.c_str(), true)) { + if (cmSystemTools::FileExists(fname, true)) { cmsys::ifstream fin; fin.open(fname.c_str()); std::string line; @@ -525,7 +535,7 @@ void cmCTestMultiProcessHandler::CreateParallelTestCostList() TestSet alreadySortedTests; std::list<TestSet> priorityStack; - priorityStack.push_back(TestSet()); + priorityStack.emplace_back(); TestSet& topLevel = priorityStack.back(); // In parallel test runs add previously failed tests to the front @@ -547,7 +557,7 @@ void cmCTestMultiProcessHandler::CreateParallelTestCostList() // further dependencies exist. while (!priorityStack.back().empty()) { TestSet& previousSet = priorityStack.back(); - priorityStack.push_back(TestSet()); + priorityStack.emplace_back(); TestSet& currentSet = priorityStack.back(); for (auto const& i : previousSet) { @@ -658,7 +668,7 @@ void cmCTestMultiProcessHandler::PrintTestList() cmWorkingDirectory workdir(p.Directory); - cmCTestRunTest testRun(this->TestHandler); + cmCTestRunTest testRun(*this); testRun.SetIndex(p.Index); testRun.SetTestProperties(&p); testRun.ComputeArguments(); // logs the command in verbose mode @@ -731,7 +741,7 @@ void cmCTestMultiProcessHandler::CheckResume() std::string fname = this->CTest->GetBinaryDir() + "/Testing/Temporary/CTestCheckpoint.txt"; if (this->CTest->GetFailover()) { - if (cmSystemTools::FileExists(fname.c_str(), true)) { + if (cmSystemTools::FileExists(fname, true)) { *this->TestHandler->LogFile << "Resuming previously interrupted test set" << std::endl << "----------------------------------------------------------" @@ -746,7 +756,7 @@ void cmCTestMultiProcessHandler::CheckResume() } fin.close(); } - } else if (cmSystemTools::FileExists(fname.c_str(), true)) { + } else if (cmSystemTools::FileExists(fname, true)) { cmSystemTools::RemoveFile(fname); } } diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h index dccc2c8..7837ff9 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.h +++ b/Source/CTest/cmCTestMultiProcessHandler.h @@ -12,6 +12,8 @@ #include <string> #include <vector> +#include "cm_uv.h" + class cmCTest; class cmCTestRunTest; @@ -23,6 +25,7 @@ class cmCTestRunTest; class cmCTestMultiProcessHandler { friend class TestComparator; + friend class cmCTestRunTest; public: struct TestSet : public std::set<int> @@ -75,7 +78,7 @@ protected: // Start the next test or tests as many as are allowed by // ParallelLevel void StartNextTests(); - void StartTestProcess(int test); + bool StartTestProcess(int test); bool StartTest(int test); // Mark the checkpoint for the given test void WriteCheckpoint(int index); @@ -95,9 +98,8 @@ protected: // Removes the checkpoint file void MarkFinished(); void EraseTest(int index); - // Return true if there are still tests running - // check all running processes for output and exit case - bool CheckOutput(); + void FinishTestProcess(cmCTestRunTest* runner, bool started); + void RemoveTest(int index); // Check if we need to resume an interrupted test set void CheckResume(); @@ -130,7 +132,7 @@ protected: std::vector<cmCTestTestHandler::cmCTestTestResult>* TestResults; size_t ParallelLevel; // max number of process that can be run at once unsigned long TestLoad; - std::set<cmCTestRunTest*> RunningTests; // current running tests + uv_loop_t Loop; cmCTestTestHandler* TestHandler; cmCTest* CTest; bool HasCycles; diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index abdb643..30ad38c 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -4,28 +4,28 @@ #include "cmCTest.h" #include "cmCTestMemCheckHandler.h" -#include "cmCTestTestHandler.h" +#include "cmCTestMultiProcessHandler.h" #include "cmProcess.h" #include "cmSystemTools.h" #include "cmWorkingDirectory.h" -#include "cm_curl.h" #include "cm_zlib.h" #include "cmsys/Base64.h" -#include "cmsys/Process.h" #include "cmsys/RegularExpression.hxx" +#include <chrono> +#include <cmAlgorithms.h> #include <iomanip> +#include <ratio> #include <sstream> #include <stdio.h> -#include <time.h> #include <utility> -cmCTestRunTest::cmCTestRunTest(cmCTestTestHandler* handler) +cmCTestRunTest::cmCTestRunTest(cmCTestMultiProcessHandler& multiHandler) + : MultiTestHandler(multiHandler) { - this->CTest = handler->CTest; - this->TestHandler = handler; - this->TestProcess = nullptr; - this->TestResult.ExecutionTime = 0; + this->CTest = multiHandler.CTest; + this->TestHandler = multiHandler.TestHandler; + this->TestResult.ExecutionTime = cmDuration::zero(); this->TestResult.ReturnValue = 0; this->TestResult.Status = cmCTestTestHandler::NOT_RUN; this->TestResult.TestCount = 0; @@ -33,57 +33,37 @@ cmCTestRunTest::cmCTestRunTest(cmCTestTestHandler* handler) this->ProcessOutput.clear(); this->CompressedOutput.clear(); this->CompressionRatio = 2; - this->StopTimePassed = false; this->NumberOfRunsLeft = 1; // default to 1 run of the test this->RunUntilFail = false; // default to run the test once this->RunAgain = false; // default to not having to run again } -cmCTestRunTest::~cmCTestRunTest() +void cmCTestRunTest::CheckOutput(std::string const& line) { -} - -bool cmCTestRunTest::CheckOutput() -{ - // Read lines for up to 0.1 seconds of total time. - double timeout = 0.1; - double timeEnd = cmSystemTools::GetTime() + timeout; - std::string line; - while ((timeout = timeEnd - cmSystemTools::GetTime(), timeout > 0)) { - int p = this->TestProcess->GetNextOutputLine(line, timeout); - if (p == cmsysProcess_Pipe_None) { - // Process has terminated and all output read. - return false; - } - if (p == cmsysProcess_Pipe_STDOUT) { - // Store this line of output. - cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->GetIndex() - << ": " << line << std::endl); - this->ProcessOutput += line; - this->ProcessOutput += "\n"; - - // Check for TIMEOUT_AFTER_MATCH property. - if (!this->TestProperties->TimeoutRegularExpressions.empty()) { - for (auto& reg : this->TestProperties->TimeoutRegularExpressions) { - if (reg.first.find(this->ProcessOutput.c_str())) { - cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->GetIndex() - << ": " - << "Test timeout changed to " - << this->TestProperties->AlternateTimeout - << std::endl); - this->TestProcess->ResetStartTime(); - this->TestProcess->ChangeTimeout( - this->TestProperties->AlternateTimeout); - this->TestProperties->TimeoutRegularExpressions.clear(); - break; - } - } + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->GetIndex() + << ": " << line << std::endl); + this->ProcessOutput += line; + this->ProcessOutput += "\n"; + + // Check for TIMEOUT_AFTER_MATCH property. + if (!this->TestProperties->TimeoutRegularExpressions.empty()) { + for (auto& reg : this->TestProperties->TimeoutRegularExpressions) { + if (reg.first.find(this->ProcessOutput.c_str())) { + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->GetIndex() + << ": " + << "Test timeout changed to " + << std::chrono::duration_cast<std::chrono::seconds>( + this->TestProperties->AlternateTimeout) + .count() + << std::endl); + this->TestProcess->ResetStartTime(); + this->TestProcess->ChangeTimeout( + this->TestProperties->AlternateTimeout); + this->TestProperties->TimeoutRegularExpressions.clear(); + break; } - } else { // if(p == cmsysProcess_Pipe_Timeout) - break; } } - return true; } // Streamed compression of test output. The compressed data @@ -156,8 +136,8 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) this->WriteLogOutputTop(completed, total); std::string reason; bool passed = true; - int res = - started ? this->TestProcess->GetProcessStatus() : cmsysProcess_State_Error; + cmProcess::State res = + started ? this->TestProcess->GetProcessStatus() : cmProcess::State::Error; int retVal = this->TestProcess->GetExitValue(); bool forceFail = false; bool skipped = false; @@ -196,7 +176,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) } } } - if (res == cmsysProcess_State_Exited) { + if (res == cmProcess::State::Exited) { bool success = !forceFail && (retVal == 0 || !this->TestProperties->RequiredRegularExpressions.empty()); @@ -217,29 +197,29 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Failed " << reason); outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure; } - } else if (res == cmsysProcess_State_Expired) { + } else if (res == cmProcess::State::Expired) { cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Timeout "); this->TestResult.Status = cmCTestTestHandler::TIMEOUT; outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure; - } else if (res == cmsysProcess_State_Exception) { + } else if (res == cmProcess::State::Exception) { outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure; cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Exception: "); this->TestResult.ExceptionStatus = this->TestProcess->GetExitExceptionString(); switch (this->TestProcess->GetExitException()) { - case cmsysProcess_Exception_Fault: + case cmProcess::Exception::Fault: cmCTestLog(this->CTest, HANDLER_OUTPUT, "SegFault"); this->TestResult.Status = cmCTestTestHandler::SEGFAULT; break; - case cmsysProcess_Exception_Illegal: + case cmProcess::Exception::Illegal: cmCTestLog(this->CTest, HANDLER_OUTPUT, "Illegal"); this->TestResult.Status = cmCTestTestHandler::ILLEGAL; break; - case cmsysProcess_Exception_Interrupt: + case cmProcess::Exception::Interrupt: cmCTestLog(this->CTest, HANDLER_OUTPUT, "Interrupt"); this->TestResult.Status = cmCTestTestHandler::INTERRUPT; break; - case cmsysProcess_Exception_Numerical: + case cmProcess::Exception::Numerical: cmCTestLog(this->CTest, HANDLER_OUTPUT, "Numerical"); this->TestResult.Status = cmCTestTestHandler::NUMERICAL; break; @@ -250,14 +230,14 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) } } else if ("Disabled" == this->TestResult.CompletionStatus) { cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Not Run (Disabled) "); - } else // cmsysProcess_State_Error + } else // cmProcess::State::Error { cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Not Run "); } passed = this->TestResult.Status == cmCTestTestHandler::COMPLETED; char buf[1024]; - sprintf(buf, "%6.2f sec", this->TestProcess->GetTotalTime()); + sprintf(buf, "%6.2f sec", this->TestProcess->GetTotalTime().count()); cmCTestLog(this->CTest, HANDLER_OUTPUT, buf << "\n"); if (outputTestErrorsToConsole) { @@ -293,12 +273,16 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) reasonType = "Test Fail Reason"; pass = false; } - double ttime = this->TestProcess->GetTotalTime(); - int hours = static_cast<int>(ttime / (60 * 60)); - int minutes = static_cast<int>(ttime / 60) % 60; - int seconds = static_cast<int>(ttime) % 60; + auto ttime = this->TestProcess->GetTotalTime(); + auto hours = std::chrono::duration_cast<std::chrono::hours>(ttime); + ttime -= hours; + auto minutes = std::chrono::duration_cast<std::chrono::minutes>(ttime); + ttime -= minutes; + auto seconds = std::chrono::duration_cast<std::chrono::seconds>(ttime); char buffer[100]; - sprintf(buffer, "%02d:%02d:%02d", hours, minutes, seconds); + sprintf(buffer, "%02d:%02d:%02d", static_cast<unsigned>(hours.count()), + static_cast<unsigned>(minutes.count()), + static_cast<unsigned>(seconds.count())); *this->TestHandler->LogFile << "----------------------------------------------------------" << std::endl; @@ -342,7 +326,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) if (!this->NeedsToRerun()) { this->TestHandler->TestResults.push_back(this->TestResult); } - delete this->TestProcess; + this->TestProcess.reset(); return passed || skipped; } @@ -378,7 +362,7 @@ void cmCTestRunTest::ComputeWeightedCost() { double prev = static_cast<double>(this->TestProperties->PreviousRuns); double avgcost = static_cast<double>(this->TestProperties->Cost); - double current = this->TestResult.ExecutionTime; + double current = this->TestResult.ExecutionTime.count(); if (this->TestResult.Status == cmCTestTestHandler::COMPLETED) { this->TestProperties->Cost = @@ -416,7 +400,7 @@ bool cmCTestRunTest::StartTest(size_t total) // Return immediately if test is disabled if (this->TestProperties->Disabled) { this->TestResult.Properties = this->TestProperties; - this->TestResult.ExecutionTime = 0; + this->TestResult.ExecutionTime = cmDuration::zero(); this->TestResult.CompressOutput = false; this->TestResult.ReturnValue = -1; this->TestResult.CompletionStatus = "Disabled"; @@ -424,16 +408,14 @@ bool cmCTestRunTest::StartTest(size_t total) this->TestResult.TestCount = this->TestProperties->Index; this->TestResult.Name = this->TestProperties->Name; this->TestResult.Path = this->TestProperties->Directory; - this->TestProcess = new cmProcess; + this->TestProcess = cm::make_unique<cmProcess>(*this); this->TestResult.Output = "Disabled"; this->TestResult.FullCommandLine.clear(); return false; } - this->ComputeArguments(); - std::vector<std::string>& args = this->TestProperties->Args; this->TestResult.Properties = this->TestProperties; - this->TestResult.ExecutionTime = 0; + this->TestResult.ExecutionTime = cmDuration::zero(); this->TestResult.CompressOutput = false; this->TestResult.ReturnValue = -1; this->TestResult.CompletionStatus = "Failed to start"; @@ -442,8 +424,12 @@ 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; + this->TestProcess = cm::make_unique<cmProcess>(*this); std::string msg = "Failed test dependencies:"; for (std::string const& failedDep : this->FailedDependencies) { msg += " " + failedDep; @@ -457,8 +443,10 @@ 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; + this->TestProcess = cm::make_unique<cmProcess>(*this); std::string msg; if (this->CTest->GetConfigType().empty()) { msg = "Test not available without configuration."; @@ -479,9 +467,9 @@ bool cmCTestRunTest::StartTest(size_t total) // Check if all required files exist for (std::string const& file : this->TestProperties->RequiredFiles) { - if (!cmSystemTools::FileExists(file.c_str())) { + if (!cmSystemTools::FileExists(file)) { // Required file was not found - this->TestProcess = new cmProcess; + this->TestProcess = cm::make_unique<cmProcess>(*this); *this->TestHandler->LogFile << "Unable to find required file: " << file << std::endl; cmCTestLog(this->CTest, ERROR_MESSAGE, @@ -497,7 +485,7 @@ bool cmCTestRunTest::StartTest(size_t total) if (this->ActualCommand.empty()) { // if the command was not found create a TestResult object // that has that information - this->TestProcess = new cmProcess; + this->TestProcess = cm::make_unique<cmProcess>(*this); *this->TestHandler->LogFile << "Unable to find executable: " << args[1] << std::endl; cmCTestLog(this->CTest, ERROR_MESSAGE, @@ -510,11 +498,22 @@ bool cmCTestRunTest::StartTest(size_t total) } this->StartTime = this->CTest->CurrentTime(); - double timeout = this->ResolveTimeout(); + auto timeout = this->TestProperties->Timeout; - if (this->StopTimePassed) { - return false; + std::chrono::system_clock::time_point stop_time = this->CTest->GetStopTime(); + if (stop_time != std::chrono::system_clock::time_point()) { + std::chrono::duration<double> stop_timeout = + (stop_time - std::chrono::system_clock::now()) % std::chrono::hours(24); + + if (stop_timeout <= std::chrono::duration<double>::zero()) { + stop_timeout = std::chrono::duration<double>::zero(); + } + if (timeout == std::chrono::duration<double>::zero() || + stop_timeout < timeout) { + timeout = stop_timeout; + } } + return this->ForkProcess(timeout, this->TestProperties->ExplicitTimeout, &this->TestProperties->Environment); } @@ -538,7 +537,7 @@ void cmCTestRunTest::ComputeArguments() ++j; // skip the executable (it will be actualCommand) } std::string testCommand = - cmSystemTools::ConvertToOutputPath(this->ActualCommand.c_str()); + cmSystemTools::ConvertToOutputPath(this->ActualCommand); // Prepends memcheck args to our command string this->TestHandler->GenerateTestCommand(this->Arguments, this->Index); @@ -591,66 +590,10 @@ void cmCTestRunTest::DartProcessing() } } -double cmCTestRunTest::ResolveTimeout() -{ - double timeout = this->TestProperties->Timeout; - - if (this->CTest->GetStopTime().empty()) { - return timeout; - } - struct tm* lctime; - time_t current_time = time(nullptr); - lctime = gmtime(¤t_time); - int gm_hour = lctime->tm_hour; - time_t gm_time = mktime(lctime); - lctime = localtime(¤t_time); - int local_hour = lctime->tm_hour; - - int tzone_offset = local_hour - gm_hour; - if (gm_time > current_time && gm_hour < local_hour) { - // this means gm_time is on the next day - tzone_offset -= 24; - } else if (gm_time < current_time && gm_hour > local_hour) { - // this means gm_time is on the previous day - tzone_offset += 24; - } - - tzone_offset *= 100; - char buf[1024]; - // add todays year day and month to the time in str because - // curl_getdate no longer assumes the day is today - sprintf(buf, "%d%02d%02d %s %+05i", lctime->tm_year + 1900, - lctime->tm_mon + 1, lctime->tm_mday, - this->CTest->GetStopTime().c_str(), tzone_offset); - - time_t stop_time = curl_getdate(buf, ¤t_time); - if (stop_time == -1) { - return timeout; - } - - // the stop time refers to the next day - if (this->CTest->NextDayStopTime) { - stop_time += 24 * 60 * 60; - } - int stop_timeout = - static_cast<int>(stop_time - current_time) % (24 * 60 * 60); - this->CTest->LastStopTimeout = stop_timeout; - - if (stop_timeout <= 0 || stop_timeout > this->CTest->LastStopTimeout) { - cmCTestLog(this->CTest, ERROR_MESSAGE, "The stop time has been passed. " - "Stopping all tests." - << std::endl); - this->StopTimePassed = true; - return 0; - } - return timeout == 0 ? stop_timeout - : (timeout < stop_timeout ? timeout : stop_timeout); -} - -bool cmCTestRunTest::ForkProcess(double testTimeOut, bool explicitTimeout, +bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout, std::vector<std::string>* environment) { - this->TestProcess = new cmProcess; + this->TestProcess = cm::make_unique<cmProcess>(*this); this->TestProcess->SetId(this->Index); this->TestProcess->SetWorkingDirectory( this->TestProperties->Directory.c_str()); @@ -658,25 +601,30 @@ bool cmCTestRunTest::ForkProcess(double testTimeOut, bool explicitTimeout, this->TestProcess->SetCommandArguments(this->Arguments); // determine how much time we have - double timeout = this->CTest->GetRemainingTimeAllowed() - 120; - if (this->CTest->GetTimeOut() > 0 && this->CTest->GetTimeOut() < timeout) { + cmDuration timeout = this->CTest->GetRemainingTimeAllowed(); + if (timeout != cmCTest::MaxDuration()) { + timeout -= std::chrono::minutes(2); + } + if (this->CTest->GetTimeOut() > cmDuration::zero() && + this->CTest->GetTimeOut() < timeout) { timeout = this->CTest->GetTimeOut(); } - if (testTimeOut > 0 && + if (testTimeOut > cmDuration::zero() && testTimeOut < this->CTest->GetRemainingTimeAllowed()) { timeout = testTimeOut; } // always have at least 1 second if we got to here - if (timeout <= 0) { - timeout = 1; + if (timeout <= cmDuration::zero()) { + timeout = std::chrono::seconds(1); } // handle timeout explicitly set to 0 - if (testTimeOut == 0 && explicitTimeout) { - timeout = 0; + if (testTimeOut == cmDuration::zero() && explicitTimeout) { + timeout = cmDuration::zero(); } cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->Index << ": " - << "Test timeout computed to be: " << timeout << "\n", + << "Test timeout computed to be: " + << cmDurationTo<unsigned int>(timeout) << "\n", this->TestHandler->GetQuiet()); this->TestProcess->SetTimeout(timeout); @@ -689,7 +637,7 @@ bool cmCTestRunTest::ForkProcess(double testTimeOut, bool explicitTimeout, cmSystemTools::AppendEnv(*environment); } - return this->TestProcess->StartProcess(); + return this->TestProcess->StartProcess(this->MultiTestHandler.Loop); } void cmCTestRunTest::WriteLogOutputTop(size_t completed, size_t total) @@ -763,3 +711,8 @@ void cmCTestRunTest::WriteLogOutputTop(size_t completed, size_t total) cmCTestLog(this->CTest, DEBUG, "Testing " << this->TestProperties->Name << " ... "); } + +void cmCTestRunTest::FinalizeTest() +{ + this->MultiTestHandler.FinishTestProcess(this, true); +} diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h index d3bb229..4d57357 100644 --- a/Source/CTest/cmCTestRunTest.h +++ b/Source/CTest/cmCTestRunTest.h @@ -11,9 +11,11 @@ #include <vector> #include "cmCTestTestHandler.h" +#include "cmDuration.h" +#include "cmProcess.h" // IWYU pragma: keep (for unique_ptr) class cmCTest; -class cmProcess; +class cmCTestMultiProcessHandler; /** \class cmRunTest * \brief represents a single test to be run @@ -23,8 +25,9 @@ class cmProcess; class cmCTestRunTest { public: - cmCTestRunTest(cmCTestTestHandler* handler); - ~cmCTestRunTest(); + explicit cmCTestRunTest(cmCTestMultiProcessHandler& multiHandler); + + ~cmCTestRunTest() = default; void SetNumberOfRuns(int n) { this->NumberOfRunsLeft = n; } void SetRunUntilFailOn() { this->RunUntilFail = true; } @@ -49,15 +52,13 @@ public: std::string GetProcessOutput() { return this->ProcessOutput; } - bool IsStopTimePassed() { return this->StopTimePassed; } - cmCTestTestHandler::cmCTestTestResult GetTestResults() { return this->TestResult; } // Read and store output. Returns true if it must be called again. - bool CheckOutput(); + void CheckOutput(std::string const& line); // Compresses the output, writing to CompressedOutput void CompressOutput(); @@ -73,13 +74,15 @@ public: bool StartAgain(); + cmCTest* GetCTest() const { return this->CTest; } + + void FinalizeTest(); + private: bool NeedsToRerun(); void DartProcessing(); void ExeNotFound(std::string exe); - // Figures out a final timeout which is min(STOP_TIME, NOW+TIMEOUT) - double ResolveTimeout(); - bool ForkProcess(double testTimeOut, bool explicitTimeout, + bool ForkProcess(cmDuration testTimeOut, bool explicitTimeout, std::vector<std::string>* environment); void WriteLogOutputTop(size_t completed, size_t total); // Run post processing of the process output for MemCheck @@ -89,26 +92,18 @@ private: // Pointer back to the "parent"; the handler that invoked this test run cmCTestTestHandler* TestHandler; cmCTest* CTest; - cmProcess* TestProcess; - // If the executable to run is ctest, don't create a new process; - // just instantiate a new cmTest. (Can be disabled for a single test - // if this option is set to false.) - // bool OptimizeForCTest; - - bool UsePrefixCommand; - std::string PrefixCommand; - + std::unique_ptr<cmProcess> TestProcess; std::string ProcessOutput; std::string CompressedOutput; double CompressionRatio; // The test results cmCTestTestHandler::cmCTestTestResult TestResult; + cmCTestMultiProcessHandler& MultiTestHandler; int Index; std::set<std::string> FailedDependencies; std::string StartTime; std::string ActualCommand; std::vector<std::string> Arguments; - bool StopTimePassed; bool RunUntilFail; int NumberOfRunsLeft; bool RunAgain; diff --git a/Source/CTest/cmCTestSVN.cxx b/Source/CTest/cmCTestSVN.cxx index ce96224..73184fc 100644 --- a/Source/CTest/cmCTestSVN.cxx +++ b/Source/CTest/cmCTestSVN.cxx @@ -515,7 +515,7 @@ private: } else { local_path = path; } - this->SVN->Repositories.push_back(SVNInfo(local_path.c_str())); + this->SVN->Repositories.emplace_back(local_path.c_str()); } }; @@ -526,7 +526,7 @@ bool cmCTestSVN::LoadRepositories() } // Info for root repository - this->Repositories.push_back(SVNInfo("")); + this->Repositories.emplace_back(""); this->RootInfo = &(this->Repositories.back()); // Run "svn status" to get the list of external repositories diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx index fdd9622..e0bffd4 100644 --- a/Source/CTest/cmCTestScriptHandler.cxx +++ b/Source/CTest/cmCTestScriptHandler.cxx @@ -5,6 +5,7 @@ #include "cmsys/Directory.hxx" #include "cmsys/Process.h" #include <map> +#include <ratio> #include <sstream> #include <stdio.h> #include <stdlib.h> @@ -26,6 +27,7 @@ #include "cmCTestTestCommand.h" #include "cmCTestUpdateCommand.h" #include "cmCTestUploadCommand.h" +#include "cmDuration.h" #include "cmFunctionBlocker.h" #include "cmGeneratedFileStream.h" #include "cmGlobalGenerator.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 = cmDurationTo<unsigned int>(std::chrono::steady_clock::now() - + this->ScriptStartTime); + auto timeString = std::to_string(itime); + this->Makefile->AddDefinition("CTEST_ELAPSED_TIME", timeString.c_str()); } } @@ -206,7 +207,8 @@ int cmCTestScriptHandler::ExecuteScript(const std::string& total_script_arg) std::vector<char> out; std::vector<char> err; std::string line; - int pipe = cmSystemTools::WaitForLine(cp, line, 100.0, out, err); + int pipe = + cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out, err); while (pipe != cmsysProcess_Pipe_None) { cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Output: " << line << "\n"); @@ -215,7 +217,8 @@ int cmCTestScriptHandler::ExecuteScript(const std::string& total_script_arg) } else if (pipe == cmsysProcess_Pipe_STDOUT) { cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, line << "\n"); } - pipe = cmSystemTools::WaitForLine(cp, line, 100, out, err); + pipe = cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out, + err); } // Properly handle output of the build command @@ -324,7 +327,7 @@ int cmCTestScriptHandler::ReadInScript(const std::string& total_script_arg) script_arg = total_script_arg.substr(comma_pos + 1); } // make sure the file exists - if (!cmSystemTools::FileExists(script.c_str())) { + if (!cmSystemTools::FileExists(script)) { cmSystemTools::Error("Cannot find file: ", script.c_str()); return 1; } @@ -343,6 +346,7 @@ int cmCTestScriptHandler::ReadInScript(const std::string& total_script_arg) this->Makefile->AddDefinition("CMAKE_EXECUTABLE_NAME", cmSystemTools::GetCMakeCommand().c_str()); this->Makefile->AddDefinition("CTEST_RUN_CURRENT_SCRIPT", true); + this->SetRunCurrentScript(true); this->UpdateElapsedTime(); // add the script arg if defined @@ -507,7 +511,7 @@ int cmCTestScriptHandler::RunConfigurationScript( int result; - this->ScriptStartTime = cmSystemTools::GetTime(); + this->ScriptStartTime = std::chrono::steady_clock::now(); // read in the script if (pscope) { @@ -524,7 +528,8 @@ int cmCTestScriptHandler::RunConfigurationScript( } // only run the curent script if we should - if (this->Makefile && this->Makefile->IsOn("CTEST_RUN_CURRENT_SCRIPT")) { + if (this->Makefile && this->Makefile->IsOn("CTEST_RUN_CURRENT_SCRIPT") && + this->ShouldRunCurrentScript) { return this->RunCurrentScript(); } return result; @@ -535,7 +540,7 @@ int cmCTestScriptHandler::RunCurrentScript() int result; // do not run twice - this->Makefile->AddDefinition("CTEST_RUN_CURRENT_SCRIPT", false); + this->SetRunCurrentScript(false); // no popup widows cmSystemTools::SetRunCommandHideConsole(true); @@ -558,22 +563,25 @@ 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() + cmDuration(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 = cmDuration(this->MinimumInterval); + if (interval < minimumInterval) { + auto sleepTime = + cmDurationTo<unsigned int>(minimumInterval - interval); + this->SleepInSeconds(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 { @@ -590,7 +598,7 @@ int cmCTestScriptHandler::CheckOutSourceDir() int retVal; bool res; - if (!cmSystemTools::FileExists(this->SourceDir.c_str()) && + if (!cmSystemTools::FileExists(this->SourceDir) && !this->CVSCheckOut.empty()) { // we must now checkout the src dir output.clear(); @@ -598,7 +606,8 @@ int cmCTestScriptHandler::CheckOutSourceDir() "Run cvs: " << this->CVSCheckOut << std::endl); res = cmSystemTools::RunSingleCommand( this->CVSCheckOut.c_str(), &output, &output, &retVal, - this->CTestRoot.c_str(), this->HandlerVerbose, 0 /*this->TimeOut*/); + this->CTestRoot.c_str(), this->HandlerVerbose, + cmDuration::zero() /*this->TimeOut*/); if (!res || retVal != 0) { cmSystemTools::Error("Unable to perform cvs checkout:\n", output.c_str()); @@ -621,10 +630,10 @@ int cmCTestScriptHandler::BackupDirectories() // backup the binary and src directories if requested if (this->Backup) { // if for some reason those directories exist then first delete them - if (cmSystemTools::FileExists(this->BackupSourceDir.c_str())) { + if (cmSystemTools::FileExists(this->BackupSourceDir)) { cmSystemTools::RemoveADirectory(this->BackupSourceDir); } - if (cmSystemTools::FileExists(this->BackupBinaryDir.c_str())) { + if (cmSystemTools::FileExists(this->BackupBinaryDir)) { cmSystemTools::RemoveADirectory(this->BackupBinaryDir); } @@ -665,7 +674,7 @@ int cmCTestScriptHandler::PerformExtraUpdates() "Run Update: " << fullCommand << std::endl); res = cmSystemTools::RunSingleCommand( fullCommand.c_str(), &output, &output, &retVal, cvsArgs[0].c_str(), - this->HandlerVerbose, 0 /*this->TimeOut*/); + this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/); if (!res || retVal != 0) { cmSystemTools::Error("Unable to perform extra updates:\n", eu.c_str(), "\nWith output:\n", output.c_str()); @@ -707,9 +716,9 @@ int cmCTestScriptHandler::RunConfigurationDashboard() } // make sure the binary directory exists if it isn't the srcdir - if (!cmSystemTools::FileExists(this->BinaryDir.c_str()) && + if (!cmSystemTools::FileExists(this->BinaryDir) && this->SourceDir != this->BinaryDir) { - if (!cmSystemTools::MakeDirectory(this->BinaryDir.c_str())) { + if (!cmSystemTools::MakeDirectory(this->BinaryDir)) { cmSystemTools::Error("Unable to create the binary directory:\n", this->BinaryDir.c_str()); this->RestoreBackupDirectories(); @@ -769,11 +778,11 @@ int cmCTestScriptHandler::RunConfigurationDashboard() "Run cmake command: " << command << std::endl); res = cmSystemTools::RunSingleCommand( command.c_str(), &output, &output, &retVal, this->BinaryDir.c_str(), - this->HandlerVerbose, 0 /*this->TimeOut*/); + this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/); if (!this->CMOutFile.empty()) { std::string cmakeOutputFile = this->CMOutFile; - if (!cmSystemTools::FileIsFullPath(cmakeOutputFile.c_str())) { + if (!cmSystemTools::FileIsFullPath(cmakeOutputFile)) { cmakeOutputFile = this->BinaryDir + "/" + cmakeOutputFile; } @@ -808,7 +817,7 @@ int cmCTestScriptHandler::RunConfigurationDashboard() "Run ctest command: " << command << std::endl); res = cmSystemTools::RunSingleCommand( command.c_str(), &output, &output, &retVal, this->BinaryDir.c_str(), - this->HandlerVerbose, 0 /*this->TimeOut*/); + this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/); // did something critical fail in ctest if (!res || cmakeFailed || retVal & cmCTest::BUILD_ERRORS) { @@ -830,7 +839,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); @@ -867,10 +876,10 @@ void cmCTestScriptHandler::RestoreBackupDirectories() // the backed up dirs if (this->Backup) { // if for some reason those directories exist then first delete them - if (cmSystemTools::FileExists(this->SourceDir.c_str())) { + if (cmSystemTools::FileExists(this->SourceDir)) { cmSystemTools::RemoveADirectory(this->SourceDir); } - if (cmSystemTools::FileExists(this->BinaryDir.c_str())) { + if (cmSystemTools::FileExists(this->BinaryDir)) { cmSystemTools::RemoveADirectory(this->BinaryDir); } // rename the src and binary directories @@ -909,7 +918,7 @@ bool cmCTestScriptHandler::EmptyBinaryDirectory(const char* sname) std::string check = sname; check += "/CMakeCache.txt"; - if (!cmSystemTools::FileExists(check.c_str())) { + if (!cmSystemTools::FileExists(check)) { return false; } @@ -955,19 +964,26 @@ bool cmCTestScriptHandler::TryToRemoveBinaryDirectoryOnce( return cmSystemTools::RemoveADirectory(directoryPath); } -double cmCTestScriptHandler::GetRemainingTimeAllowed() +cmDuration cmCTestScriptHandler::GetRemainingTimeAllowed() { if (!this->Makefile) { - return 1.0e7; + return cmCTest::MaxDuration(); } const char* timelimitS = this->Makefile->GetDefinition("CTEST_TIME_LIMIT"); if (!timelimitS) { - return 1.0e7; + return cmCTest::MaxDuration(); } - double timelimit = atof(timelimitS); + auto timelimit = cmDuration(atof(timelimitS)); - return timelimit - cmSystemTools::GetTime() + this->ScriptStartTime; + auto duration = std::chrono::duration_cast<cmDuration>( + std::chrono::steady_clock::now() - this->ScriptStartTime); + return (timelimit - duration); +} + +void cmCTestScriptHandler::SetRunCurrentScript(bool value) +{ + this->ShouldRunCurrentScript = value; } diff --git a/Source/CTest/cmCTestScriptHandler.h b/Source/CTest/cmCTestScriptHandler.h index b6cd97b..cf0762e 100644 --- a/Source/CTest/cmCTestScriptHandler.h +++ b/Source/CTest/cmCTestScriptHandler.h @@ -6,7 +6,9 @@ #include "cmConfigure.h" // IWYU pragma: keep #include "cmCTestGenericHandler.h" +#include "cmDuration.h" +#include <chrono> #include <string> #include <vector> @@ -93,9 +95,9 @@ public: /** * Return the time remaianing that the script is allowed to run in * seconds if the user has set the variable CTEST_TIME_LIMIT. If that has - * not been set it returns 1e7 seconds + * not been set it returns a very large value. */ - double GetRemainingTimeAllowed(); + cmDuration GetRemainingTimeAllowed(); cmCTestScriptHandler(); ~cmCTestScriptHandler() override; @@ -104,6 +106,9 @@ public: void CreateCMake(); cmake* GetCMake() { return this->CMake; } + + void SetRunCurrentScript(bool value); + private: // reads in a script int ReadInScript(const std::string& total_script_arg); @@ -134,6 +139,8 @@ private: std::vector<std::string> ConfigurationScripts; std::vector<bool> ScriptProcessScope; + bool ShouldRunCurrentScript; + bool Backup; bool EmptyBinDir; bool EmptyBinDirOnce; @@ -156,7 +163,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/cmCTestStartCommand.cxx b/Source/CTest/cmCTestStartCommand.cxx index 4f0d87b..38ee623 100644 --- a/Source/CTest/cmCTestStartCommand.cxx +++ b/Source/CTest/cmCTestStartCommand.cxx @@ -126,7 +126,7 @@ bool cmCTestStartCommand::InitialPass(std::vector<std::string> const& args, return false; } - this->Makefile->AddDefinition("CTEST_RUN_CURRENT_SCRIPT", "OFF"); + this->CTest->SetRunCurrentScript(false); this->CTest->SetSuppressUpdatingCTestConfiguration(true); int model = this->CTest->GetTestModelFromString(smodel); this->CTest->SetTestModel(model); diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx index 1794ca6..34adb4a 100644 --- a/Source/CTest/cmCTestSubmitCommand.cxx +++ b/Source/CTest/cmCTestSubmitCommand.cxx @@ -229,7 +229,7 @@ bool cmCTestSubmitCommand::CheckArgumentValue(std::string const& arg) } if (this->ArgumentDoing == ArgumentDoingFiles) { - if (cmSystemTools::FileExists(arg.c_str())) { + if (cmSystemTools::FileExists(arg)) { this->Files.insert(arg); } else { std::ostringstream e; diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index e51e168..08d05c8 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> @@ -15,6 +16,7 @@ #include "cmCTestScriptHandler.h" #include "cmCryptoHash.h" #include "cmCurl.h" +#include "cmDuration.h" #include "cmGeneratedFileStream.h" #include "cmProcessOutput.h" #include "cmState.h" @@ -192,13 +194,13 @@ bool cmCTestSubmitHandler::SubmitUsingFTP(const std::string& localprefix, ::curl_easy_setopt(curl, CURLOPT_UPLOAD, 1); std::string local_file = file; - if (!cmSystemTools::FileExists(local_file.c_str())) { + if (!cmSystemTools::FileExists(local_file)) { local_file = localprefix + "/" + file; } std::string upload_as = url + "/" + remoteprefix + cmSystemTools::GetFilenameName(file); - if (!cmSystemTools::FileExists(local_file.c_str())) { + if (!cmSystemTools::FileExists(local_file)) { cmCTestLog(this->CTest, ERROR_MESSAGE, " Cannot find file: " << local_file << std::endl); ::curl_easy_cleanup(curl); @@ -385,7 +387,7 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const std::string& localprefix, ::curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); std::string local_file = file; - if (!cmSystemTools::FileExists(local_file.c_str())) { + if (!cmSystemTools::FileExists(local_file)) { local_file = localprefix + "/" + file; } std::string remote_file = @@ -427,7 +429,7 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const std::string& localprefix, cmSystemTools::ComputeFileHash(local_file, cmCryptoHash::AlgoMD5); } - if (!cmSystemTools::FileExists(local_file.c_str())) { + if (!cmSystemTools::FileExists(local_file)) { cmCTestLog(this->CTest, ERROR_MESSAGE, " Cannot find file: " << local_file << std::endl); ::curl_easy_cleanup(curl); @@ -496,10 +498,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 = cmDuration( + 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 +510,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); } @@ -769,7 +772,7 @@ bool cmCTestSubmitHandler::SubmitUsingSCP(const std::string& scp_command, std::string lfname = localprefix; cmSystemTools::ConvertToUnixSlashes(lfname); lfname += "/" + file; - lfname = cmSystemTools::ConvertToOutputPath(lfname.c_str()); + lfname = cmSystemTools::ConvertToOutputPath(lfname); argv[1] = lfname.c_str(); std::string rfname = url + "/" + remoteprefix + file; argv[2] = rfname.c_str(); @@ -895,7 +898,7 @@ bool cmCTestSubmitHandler::SubmitUsingXMLRPC( xmlrpc_value* result; std::string local_file = file; - if (!cmSystemTools::FileExists(local_file.c_str())) { + if (!cmSystemTools::FileExists(local_file)) { local_file = localprefix + "/" + file; } cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, @@ -1031,11 +1034,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 +1070,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 +1080,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 +1096,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 +1170,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 +1530,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 +1549,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/cmCTestTestCommand.cxx b/Source/CTest/cmCTestTestCommand.cxx index febd39e..daedf62 100644 --- a/Source/CTest/cmCTestTestCommand.cxx +++ b/Source/CTest/cmCTestTestCommand.cxx @@ -4,9 +4,11 @@ #include "cmCTest.h" #include "cmCTestGenericHandler.h" +#include "cmDuration.h" #include "cmMakefile.h" #include "cmSystemTools.h" +#include <chrono> #include <sstream> #include <stdlib.h> #include <vector> @@ -36,14 +38,14 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler() const char* ctestTimeout = this->Makefile->GetDefinition("CTEST_TEST_TIMEOUT"); - double timeout; + cmDuration timeout; if (ctestTimeout) { - timeout = atof(ctestTimeout); + timeout = cmDuration(atof(ctestTimeout)); } else { timeout = this->CTest->GetTimeOut(); - if (timeout <= 0) { + if (timeout <= cmDuration::zero()) { // By default use timeout of 10 minutes - timeout = 600; + timeout = std::chrono::minutes(10); } } this->CTest->SetTimeOut(timeout); diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index c7ed927..84d8926 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> @@ -18,9 +19,9 @@ #include "cmAlgorithms.h" #include "cmCTest.h" -#include "cmCTestBatchTestHandler.h" #include "cmCTestMultiProcessHandler.h" #include "cmCommand.h" +#include "cmDuration.h" #include "cmGeneratedFileStream.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" @@ -69,7 +70,7 @@ bool cmCTestSubdirCommand::InitialPass(std::vector<std::string> const& args, for (std::string const& arg : args) { std::string fname; - if (cmSystemTools::FileIsFullPath(arg.c_str())) { + if (cmSystemTools::FileIsFullPath(arg)) { fname = arg; } else { fname = cwd; @@ -144,7 +145,7 @@ bool cmCTestAddSubdirectoryCommand::InitialPass( fname += "/"; fname += args[0]; - if (!cmSystemTools::FileExists(fname.c_str())) { + if (!cmSystemTools::FileExists(fname)) { // No subdirectory? So what... return true; } @@ -346,7 +347,7 @@ void cmCTestTestHandler::Initialize() { this->Superclass::Initialize(); - this->ElapsedTestingTime = -1; + this->ElapsedTestingTime = cmDuration(); this->TestResults.clear(); @@ -484,12 +485,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 +540,8 @@ int cmCTestTestHandler::ProcessHandler() this->PrintLabelOrSubprojectSummary(false); } char realBuf[1024]; - sprintf(realBuf, "%6.2f sec", clock_finish - clock_start); + cmDuration durationInSecs = clock_finish - clock_start; + sprintf(realBuf, "%6.2f sec", durationInSecs.count()); cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "\nTotal Test time (real) = " << realBuf << "\n", this->Quiet); @@ -650,7 +651,8 @@ void cmCTestTestHandler::PrintLabelOrSubprojectSummary(bool doSubProject) for (std::string const& l : p.Labels) { // only use labels found in labels if (labels.find(l) != labels.end()) { - labelTimes[l] += result.ExecutionTime * result.Properties->Processors; + labelTimes[l] += + result.ExecutionTime.count() * result.Properties->Processors; ++labelCounts[l]; } } @@ -1200,12 +1202,10 @@ 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 - : new cmCTestMultiProcessHandler; + cmCTestMultiProcessHandler* parallel = new cmCTestMultiProcessHandler; parallel->SetCTest(this->CTest); parallel->SetParallelLevel(this->CTest->GetParallelLevel()); parallel->SetTestHandler(this); @@ -1236,7 +1236,8 @@ void cmCTestTestHandler::ProcessDirectory(std::vector<std::string>& passed, p.Cost = static_cast<float>(rand()); } - if (p.Timeout == 0 && this->CTest->GetGlobalTimeout() != 0) { + if (p.Timeout == cmDuration::zero() && + this->CTest->GetGlobalTimeout() != cmDuration::zero()) { p.Timeout = this->CTest->GetGlobalTimeout(); } @@ -1267,8 +1268,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; } @@ -1317,7 +1319,7 @@ void cmCTestTestHandler::GenerateDartOutput(cmXMLWriter& xml) xml.StartElement("NamedMeasurement"); xml.Attribute("type", "numeric/double"); xml.Attribute("name", "Execution Time"); - xml.Element("Value", result.ExecutionTime); + xml.Element("Value", result.ExecutionTime.count()); xml.EndElement(); // NamedMeasurement if (!result.Reason.empty()) { const char* reasonType = "Pass Reason"; @@ -1373,8 +1375,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); } @@ -1572,7 +1576,7 @@ std::string cmCTestTestHandler::FindExecutable( // now look in the paths we specified above for (unsigned int ai = 0; ai < attempted.size() && fullPath.empty(); ++ai) { // first check without exe extension - if (cmSystemTools::FileExists(attempted[ai].c_str()) && + if (cmSystemTools::FileExists(attempted[ai]) && !cmSystemTools::FileIsDirectory(attempted[ai])) { fullPath = cmSystemTools::CollapseFullPath(attempted[ai]); resultingConfig = attemptedConfigs[ai]; @@ -1582,7 +1586,7 @@ std::string cmCTestTestHandler::FindExecutable( failed.push_back(attempted[ai]); tempPath = attempted[ai]; tempPath += cmSystemTools::GetExecutableExtension(); - if (cmSystemTools::FileExists(tempPath.c_str()) && + if (cmSystemTools::FileExists(tempPath) && !cmSystemTools::FileIsDirectory(tempPath)) { fullPath = cmSystemTools::CollapseFullPath(tempPath); resultingConfig = attemptedConfigs[ai]; @@ -1818,7 +1822,7 @@ void cmCTestTestHandler::ExpandTestsToRunInformationForRerunFailed() std::string lastTestsFailedLog = this->CTest->GetBinaryDir() + "/Testing/Temporary/" + logName; - if (!cmSystemTools::FileExists(lastTestsFailedLog.c_str())) { + if (!cmSystemTools::FileExists(lastTestsFailedLog)) { if (!this->CTest->GetShowOnly() && !this->CTest->ShouldPrintLabels()) { cmCTestLog(this->CTest, ERROR_MESSAGE, lastTestsFailedLog << " does not exist!" << std::endl); @@ -1931,7 +1935,7 @@ void cmCTestTestHandler::GenerateRegressionImages(cmXMLWriter& xml, } else if (measurementfile.find(cxml)) { const std::string& filename = cmCTest::CleanString(measurementfile.match(5)); - if (cmSystemTools::FileExists(filename.c_str())) { + if (cmSystemTools::FileExists(filename)) { long len = cmSystemTools::FileLength(filename); if (len == 0) { std::string k1 = measurementfile.match(1); @@ -2136,7 +2140,7 @@ bool cmCTestTestHandler::SetTestsProperties( rt.FixturesRequired.insert(lval.begin(), lval.end()); } if (key == "TIMEOUT") { - rt.Timeout = atof(val.c_str()); + rt.Timeout = cmDuration(atof(val.c_str())); rt.ExplicitTimeout = true; } if (key == "COST") { @@ -2152,9 +2156,7 @@ bool cmCTestTestHandler::SetTestsProperties( std::vector<std::string> lval; cmSystemTools::ExpandListArgument(val, lval); for (std::string const& cr : lval) { - rt.ErrorRegularExpressions.push_back( - std::pair<cmsys::RegularExpression, std::string>( - cmsys::RegularExpression(cr.c_str()), std::string(cr))); + rt.ErrorRegularExpressions.emplace_back(cr, cr); } } if (key == "PROCESSORS") { @@ -2200,9 +2202,7 @@ bool cmCTestTestHandler::SetTestsProperties( std::vector<std::string> lval; cmSystemTools::ExpandListArgument(val, lval); for (std::string const& cr : lval) { - rt.RequiredRegularExpressions.push_back( - std::pair<cmsys::RegularExpression, std::string>( - cmsys::RegularExpression(cr.c_str()), std::string(cr))); + rt.RequiredRegularExpressions.emplace_back(cr, cr); } } if (key == "WORKING_DIRECTORY") { @@ -2216,13 +2216,11 @@ bool cmCTestTestHandler::SetTestsProperties( "TIMEOUT_AFTER_MATCH expects two arguments, found " << propArgs.size() << std::endl); } else { - rt.AlternateTimeout = atof(propArgs[0].c_str()); + rt.AlternateTimeout = cmDuration(atof(propArgs[0].c_str())); std::vector<std::string> lval; cmSystemTools::ExpandListArgument(propArgs[1], lval); for (std::string const& cr : lval) { - rt.TimeoutRegularExpressions.push_back( - std::pair<cmsys::RegularExpression, std::string>( - cmsys::RegularExpression(cr.c_str()), std::string(cr))); + rt.TimeoutRegularExpressions.emplace_back(cr, cr); } } } @@ -2334,7 +2332,7 @@ bool cmCTestTestHandler::AddTest(const std::vector<std::string>& args) test.WillFail = false; test.Disabled = false; test.RunSerial = false; - test.Timeout = 0; + test.Timeout = cmDuration::zero(); test.ExplicitTimeout = false; test.Cost = 0; test.Processors = 1; diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index 394d20e..f4978b6 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -6,8 +6,10 @@ #include "cmConfigure.h" // IWYU pragma: keep #include "cmCTestGenericHandler.h" +#include "cmDuration.h" #include "cmsys/RegularExpression.hxx" +#include <chrono> #include <iosfwd> #include <map> #include <set> @@ -28,7 +30,6 @@ class cmCTestTestHandler : public cmCTestGenericHandler { friend class cmCTestRunTest; friend class cmCTestMultiProcessHandler; - friend class cmCTestBatchTestHandler; public: typedef cmCTestGenericHandler Superclass; @@ -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. */ @@ -123,9 +124,9 @@ public: float Cost; int PreviousRuns; bool RunSerial; - double Timeout; + cmDuration Timeout; bool ExplicitTimeout; - double AlternateTimeout; + cmDuration AlternateTimeout; int Index; // Requested number of process slots int Processors; @@ -146,7 +147,7 @@ public: std::string Path; std::string Reason; std::string FullCommandLine; - double ExecutionTime; + cmDuration ExecutionTime; int ReturnValue; int Status; std::string ExceptionStatus; @@ -198,7 +199,7 @@ protected: //! Clean test output to specified length bool CleanTestOutput(std::string& output, size_t length); - double ElapsedTestingTime; + cmDuration 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..504b210 100644 --- a/Source/CTest/cmCTestUpdateHandler.cxx +++ b/Source/CTest/cmCTestUpdateHandler.cxx @@ -17,6 +17,7 @@ #include "cmVersion.h" #include "cmXMLWriter.h" +#include <chrono> #include <memory> // IWYU pragma: keep #include <sstream> @@ -175,9 +176,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 +224,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) { @@ -257,37 +257,37 @@ int cmCTestUpdateHandler::DetectVCS(const char* dir) "Check directory: " << sourceDirectory << std::endl, this->Quiet); sourceDirectory += "/.svn"; - if (cmSystemTools::FileExists(sourceDirectory.c_str())) { + if (cmSystemTools::FileExists(sourceDirectory)) { return cmCTestUpdateHandler::e_SVN; } sourceDirectory = dir; sourceDirectory += "/CVS"; - if (cmSystemTools::FileExists(sourceDirectory.c_str())) { + if (cmSystemTools::FileExists(sourceDirectory)) { return cmCTestUpdateHandler::e_CVS; } sourceDirectory = dir; sourceDirectory += "/.bzr"; - if (cmSystemTools::FileExists(sourceDirectory.c_str())) { + if (cmSystemTools::FileExists(sourceDirectory)) { return cmCTestUpdateHandler::e_BZR; } sourceDirectory = dir; sourceDirectory += "/.git"; - if (cmSystemTools::FileExists(sourceDirectory.c_str())) { + if (cmSystemTools::FileExists(sourceDirectory)) { return cmCTestUpdateHandler::e_GIT; } sourceDirectory = dir; sourceDirectory += "/.hg"; - if (cmSystemTools::FileExists(sourceDirectory.c_str())) { + if (cmSystemTools::FileExists(sourceDirectory)) { return cmCTestUpdateHandler::e_HG; } sourceDirectory = dir; sourceDirectory += "/.p4"; - if (cmSystemTools::FileExists(sourceDirectory.c_str())) { + if (cmSystemTools::FileExists(sourceDirectory)) { return cmCTestUpdateHandler::e_P4; } sourceDirectory = dir; sourceDirectory += "/.p4config"; - if (cmSystemTools::FileExists(sourceDirectory.c_str())) { + if (cmSystemTools::FileExists(sourceDirectory)) { return cmCTestUpdateHandler::e_P4; } return cmCTestUpdateHandler::e_UNKNOWN; diff --git a/Source/CTest/cmCTestUploadCommand.cxx b/Source/CTest/cmCTestUploadCommand.cxx index d85f35f..ec78c1e 100644 --- a/Source/CTest/cmCTestUploadCommand.cxx +++ b/Source/CTest/cmCTestUploadCommand.cxx @@ -51,7 +51,7 @@ bool cmCTestUploadCommand::CheckArgumentValue(std::string const& arg) return true; } if (this->ArgumentDoing == ArgumentDoingFiles) { - if (cmSystemTools::FileExists(arg.c_str())) { + if (cmSystemTools::FileExists(arg)) { this->Files.insert(arg); return true; } diff --git a/Source/CTest/cmCTestVC.cxx b/Source/CTest/cmCTestVC.cxx index fd7f37a..13fa6e1 100644 --- a/Source/CTest/cmCTestVC.cxx +++ b/Source/CTest/cmCTestVC.cxx @@ -47,7 +47,7 @@ bool cmCTestVC::InitialCheckout(const char* command) std::string parent = cmSystemTools::GetFilenamePath(this->SourceDirectory); cmCTestLog(this->CTest, HANDLER_OUTPUT, " Perform checkout in directory: " << parent << "\n"); - if (!cmSystemTools::MakeDirectory(parent.c_str())) { + if (!cmSystemTools::MakeDirectory(parent)) { cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot create directory: " << parent << std::endl); return false; diff --git a/Source/CTest/cmParseCoberturaCoverage.cxx b/Source/CTest/cmParseCoberturaCoverage.cxx index 61ce7d4..5bb6424 100644 --- a/Source/CTest/cmParseCoberturaCoverage.cxx +++ b/Source/CTest/cmParseCoberturaCoverage.cxx @@ -83,7 +83,7 @@ protected: // binary directories. for (std::string const& filePath : FilePaths) { finalpath = filePath + "/" + filename; - if (cmSystemTools::FileExists(finalpath.c_str())) { + if (cmSystemTools::FileExists(finalpath)) { this->CurFileName = finalpath; break; } 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/cmParseMumpsCoverage.cxx b/Source/CTest/cmParseMumpsCoverage.cxx index 1419743..18412ba 100644 --- a/Source/CTest/cmParseMumpsCoverage.cxx +++ b/Source/CTest/cmParseMumpsCoverage.cxx @@ -114,7 +114,7 @@ bool cmParseMumpsCoverage::LoadPackages(const char* d) for (std::string& file : glob.GetFiles()) { std::string name = cmSystemTools::GetFilenameName(file); this->RoutineToDirectory[name.substr(0, name.size() - 2)] = file; - // initialze each file, this is left out until CDash is fixed + // initialize each file, this is left out until CDash is fixed // to handle large numbers of files this->InitializeMumpsFile(file); } diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx index f3c191b..09ed0a9 100644 --- a/Source/CTest/cmProcess.cxx +++ b/Source/CTest/cmProcess.cxx @@ -2,24 +2,77 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmProcess.h" -#include "cmProcessOutput.h" -#include "cmSystemTools.h" +#include "cmCTest.h" +#include "cmCTestRunTest.h" +#include "cmCTestTestHandler.h" +#include "cmsys/Process.h" + +#include <algorithm> +#include <fcntl.h> #include <iostream> +#include <signal.h> +#include <string> +#if !defined(_WIN32) +#include <unistd.h> +#endif + +#define CM_PROCESS_BUF_SIZE 65536 + +#if defined(_WIN32) && !defined(__CYGWIN__) +#include <io.h> + +static int cmProcessGetPipes(int* fds) +{ + SECURITY_ATTRIBUTES attr; + HANDLE readh, writeh; + attr.nLength = sizeof(attr); + attr.lpSecurityDescriptor = nullptr; + attr.bInheritHandle = FALSE; + if (!CreatePipe(&readh, &writeh, &attr, 0)) + return uv_translate_sys_error(GetLastError()); + fds[0] = _open_osfhandle((intptr_t)readh, 0); + fds[1] = _open_osfhandle((intptr_t)writeh, 0); + if (fds[0] == -1 || fds[1] == -1) { + CloseHandle(readh); + CloseHandle(writeh); + return uv_translate_sys_error(GetLastError()); + } + return 0; +} +#else +#include <errno.h> -cmProcess::cmProcess() +static int cmProcessGetPipes(int* fds) { - this->Process = nullptr; - this->Timeout = 0; - this->TotalTime = 0; + if (pipe(fds) == -1) { + return uv_translate_sys_error(errno); + } + + if (fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 || + fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) { + close(fds[0]); + close(fds[1]); + return uv_translate_sys_error(errno); + } + return 0; +} +#endif + +cmProcess::cmProcess(cmCTestRunTest& runner) + : Runner(runner) + , Conv(cmProcessOutput::UTF8, CM_PROCESS_BUF_SIZE) +{ + this->Timeout = cmDuration::zero(); + this->TotalTime = cmDuration::zero(); this->ExitValue = 0; this->Id = 0; - this->StartTime = 0; + this->StartTime = std::chrono::steady_clock::time_point(); } cmProcess::~cmProcess() { - cmsysProcess_Delete(this->Process); } + void cmProcess::SetCommand(const char* command) { this->Command = command; @@ -30,12 +83,13 @@ void cmProcess::SetCommandArguments(std::vector<std::string> const& args) this->Arguments = args; } -bool cmProcess::StartProcess() +bool cmProcess::StartProcess(uv_loop_t& loop) { + this->ProcessState = cmProcess::State::Error; 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()); @@ -44,17 +98,83 @@ bool cmProcess::StartProcess() this->ProcessArgs.push_back(arg.c_str()); } this->ProcessArgs.push_back(nullptr); // null terminate the list - this->Process = cmsysProcess_New(); - cmsysProcess_SetCommand(this->Process, &*this->ProcessArgs.begin()); - if (!this->WorkingDirectory.empty()) { - cmsysProcess_SetWorkingDirectory(this->Process, - this->WorkingDirectory.c_str()); + + cm::uv_timer_ptr timer; + int status = timer.init(loop, this); + if (status != 0) { + cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE, + "Error initializing timer: " << uv_strerror(status) + << std::endl); + return false; + } + + cm::uv_pipe_ptr pipe_writer; + cm::uv_pipe_ptr pipe_reader; + + pipe_writer.init(loop, 0); + pipe_reader.init(loop, 0, this); + + int fds[2] = { -1, -1 }; + status = cmProcessGetPipes(fds); + if (status != 0) { + cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE, + "Error initializing pipe: " << uv_strerror(status) + << std::endl); + return false; + } + + uv_pipe_open(pipe_reader, fds[0]); + uv_pipe_open(pipe_writer, fds[1]); + + uv_stdio_container_t stdio[3]; + stdio[0].flags = UV_IGNORE; + stdio[1].flags = UV_INHERIT_STREAM; + stdio[1].data.stream = pipe_writer; + stdio[2] = stdio[1]; + + uv_process_options_t options = uv_process_options_t(); + options.file = this->Command.data(); + options.args = const_cast<char**>(this->ProcessArgs.data()); + options.stdio_count = 3; // in, out and err + options.exit_cb = &cmProcess::OnExitCB; + options.stdio = stdio; + + status = + uv_read_start(pipe_reader, &cmProcess::OnAllocateCB, &cmProcess::OnReadCB); + + if (status != 0) { + cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE, + "Error starting read events: " << uv_strerror(status) + << std::endl); + return false; + } + + status = this->Process.spawn(loop, options, this); + if (status != 0) { + cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE, "Process not started\n " + << this->Command << "\n[" << uv_strerror(status) << "]\n"); + return false; + } + + this->PipeReader = std::move(pipe_reader); + this->Timer = std::move(timer); + + this->StartTimer(); + + this->ProcessState = cmProcess::State::Executing; + return true; +} + +void cmProcess::StartTimer() +{ + auto properties = this->Runner.GetTestProperties(); + auto msec = + std::chrono::duration_cast<std::chrono::milliseconds>(this->Timeout); + + if (msec != std::chrono::milliseconds(0) || !properties->ExplicitTimeout) { + this->Timer.start(&cmProcess::OnTimeoutCB, + static_cast<uint64_t>(msec.count()), 0); } - cmsysProcess_SetTimeout(this->Process, this->Timeout); - cmsysProcess_SetOption(this->Process, cmsysProcess_Option_MergeOutput, 1); - cmsysProcess_Execute(this->Process); - return (cmsysProcess_GetState(this->Process) == - cmsysProcess_State_Executing); } bool cmProcess::Buffer::GetLine(std::string& line) @@ -101,145 +221,499 @@ bool cmProcess::Buffer::GetLast(std::string& line) return false; } -int cmProcess::GetNextOutputLine(std::string& line, double timeout) +void cmProcess::OnReadCB(uv_stream_t* stream, ssize_t nread, + const uv_buf_t* buf) { - cmProcessOutput processOutput(cmProcessOutput::UTF8); - std::string strdata; - for (;;) { - // Look for lines already buffered. - if (this->Output.GetLine(line)) { - return cmsysProcess_Pipe_STDOUT; - } + auto self = static_cast<cmProcess*>(stream->data); + self->OnRead(nread, buf); +} - // Check for more data from the process. - char* data; - int length; - int p = cmsysProcess_WaitForData(this->Process, &data, &length, &timeout); - if (p == cmsysProcess_Pipe_Timeout) { - return cmsysProcess_Pipe_Timeout; - } - if (p == cmsysProcess_Pipe_STDOUT) { - processOutput.DecodeText(data, length, strdata); - this->Output.insert(this->Output.end(), strdata.begin(), strdata.end()); - } else { // p == cmsysProcess_Pipe_None - // The process will provide no more data. - break; +void cmProcess::OnRead(ssize_t nread, const uv_buf_t* buf) +{ + std::string line; + if (nread > 0) { + std::string strdata; + this->Conv.DecodeText(buf->base, static_cast<size_t>(nread), strdata); + this->Output.insert(this->Output.end(), strdata.begin(), strdata.end()); + + while (this->Output.GetLine(line)) { + this->Runner.CheckOutput(line); + line.clear(); } + + return; } - processOutput.DecodeText(std::string(), strdata); - if (!strdata.empty()) { - this->Output.insert(this->Output.end(), strdata.begin(), strdata.end()); + + if (nread == 0) { + return; + } + + // The process will provide no more data. + if (nread != UV_EOF) { + auto error = static_cast<int>(nread); + cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE, + "Error reading stream: " << uv_strerror(error) << std::endl); } // Look for partial last lines. if (this->Output.GetLast(line)) { - return cmsysProcess_Pipe_STDOUT; + this->Runner.CheckOutput(line); + } + + this->ReadHandleClosed = true; + this->PipeReader.reset(); + if (this->ProcessHandleClosed) { + uv_timer_stop(this->Timer); + this->Runner.FinalizeTest(); + } +} + +void cmProcess::OnAllocateCB(uv_handle_t* handle, size_t suggested_size, + uv_buf_t* buf) +{ + auto self = static_cast<cmProcess*>(handle->data); + self->OnAllocate(suggested_size, buf); +} + +void cmProcess::OnAllocate(size_t /*suggested_size*/, uv_buf_t* buf) +{ + if (this->Buf.size() != CM_PROCESS_BUF_SIZE) { + this->Buf.resize(CM_PROCESS_BUF_SIZE); } - // No more data. Wait for process exit. - if (!cmsysProcess_WaitForExit(this->Process, &timeout)) { - return cmsysProcess_Pipe_Timeout; + *buf = + uv_buf_init(this->Buf.data(), static_cast<unsigned int>(this->Buf.size())); +} + +void cmProcess::OnTimeoutCB(uv_timer_t* timer) +{ + auto self = static_cast<cmProcess*>(timer->data); + self->OnTimeout(); +} + +void cmProcess::OnTimeout() +{ + if (this->ProcessState != cmProcess::State::Executing) { + return; + } + this->ProcessState = cmProcess::State::Expired; + bool const was_still_reading = !this->ReadHandleClosed; + if (!this->ReadHandleClosed) { + this->ReadHandleClosed = true; + this->PipeReader.reset(); + } + if (!this->ProcessHandleClosed) { + // Kill the child and let our on-exit handler finish the test. + cmsysProcess_KillPID(static_cast<unsigned long>(this->Process->pid)); + } else if (was_still_reading) { + // Our on-exit handler already ran but did not finish the test + // because we were still reading output. We've just dropped + // our read handler, so we need to finish the test now. + this->Runner.FinalizeTest(); + } +} + +void cmProcess::OnExitCB(uv_process_t* process, int64_t exit_status, + int term_signal) +{ + auto self = static_cast<cmProcess*>(process->data); + self->OnExit(exit_status, term_signal); +} + +void cmProcess::OnExit(int64_t exit_status, int term_signal) +{ + if (this->ProcessState != cmProcess::State::Expired) { + if ( +#if defined(_WIN32) + ((DWORD)exit_status & 0xF0000000) == 0xC0000000 +#else + term_signal != 0 +#endif + ) { + this->ProcessState = cmProcess::State::Exception; + } else { + this->ProcessState = cmProcess::State::Exited; + } } // Record exit information. - this->ExitValue = cmsysProcess_GetExitValue(this->Process); - this->TotalTime = cmSystemTools::GetTime() - this->StartTime; + this->ExitValue = static_cast<int>(exit_status); + this->Signal = term_signal; + this->TotalTime = std::chrono::steady_clock::now() - this->StartTime; // 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 // duration here. - if (this->TotalTime <= 0.0) { - this->TotalTime = 0.0; - } - // std::cerr << "Time to run: " << this->TotalTime << "\n"; - return cmsysProcess_Pipe_None; -} - -// return the process status -int cmProcess::GetProcessStatus() -{ - if (!this->Process) { - return cmsysProcess_State_Exited; - } - return cmsysProcess_GetState(this->Process); -} - -int cmProcess::ReportStatus() -{ - int result = 1; - switch (cmsysProcess_GetState(this->Process)) { - case cmsysProcess_State_Starting: { - std::cerr << "cmProcess: Never started " << this->Command - << " process.\n"; - } break; - case cmsysProcess_State_Error: { - std::cerr << "cmProcess: Error executing " << this->Command - << " process: " << cmsysProcess_GetErrorString(this->Process) - << "\n"; - } break; - case cmsysProcess_State_Exception: { - std::cerr << "cmProcess: " << this->Command - << " process exited with an exception: "; - switch (cmsysProcess_GetExitException(this->Process)) { - case cmsysProcess_Exception_None: { - std::cerr << "None"; - } break; - case cmsysProcess_Exception_Fault: { - std::cerr << "Segmentation fault"; - } break; - case cmsysProcess_Exception_Illegal: { - std::cerr << "Illegal instruction"; - } break; - case cmsysProcess_Exception_Interrupt: { - std::cerr << "Interrupted by user"; - } break; - case cmsysProcess_Exception_Numerical: { - std::cerr << "Numerical exception"; - } break; - case cmsysProcess_Exception_Other: { - std::cerr << "Unknown"; - } break; - } - std::cerr << "\n"; - } break; - case cmsysProcess_State_Executing: { - std::cerr << "cmProcess: Never terminated " << this->Command - << " process.\n"; - } break; - case cmsysProcess_State_Exited: { - result = cmsysProcess_GetExitValue(this->Process); - std::cerr << "cmProcess: " << this->Command - << " process exited with code " << result << "\n"; - } break; - case cmsysProcess_State_Expired: { - std::cerr << "cmProcess: killed " << this->Command - << " process due to timeout.\n"; - } break; - case cmsysProcess_State_Killed: { - std::cerr << "cmProcess: killed " << this->Command << " process.\n"; - } break; - } - return result; -} - -void cmProcess::ChangeTimeout(double t) + if (this->TotalTime <= cmDuration::zero()) { + this->TotalTime = cmDuration::zero(); + } + + this->ProcessHandleClosed = true; + if (this->ReadHandleClosed) { + uv_timer_stop(this->Timer); + this->Runner.FinalizeTest(); + } +} + +cmProcess::State cmProcess::GetProcessStatus() +{ + return this->ProcessState; +} + +void cmProcess::ChangeTimeout(cmDuration t) { this->Timeout = t; - cmsysProcess_SetTimeout(this->Process, this->Timeout); + this->StartTimer(); } void cmProcess::ResetStartTime() { - cmsysProcess_ResetStartTime(this->Process); - this->StartTime = cmSystemTools::GetTime(); + this->StartTime = std::chrono::steady_clock::now(); } -int cmProcess::GetExitException() +cmProcess::Exception cmProcess::GetExitException() { - return cmsysProcess_GetExitException(this->Process); + auto exception = Exception::None; +#if defined(_WIN32) && !defined(__CYGWIN__) + auto exit_code = (DWORD) this->ExitValue; + if ((exit_code & 0xF0000000) != 0xC0000000) { + return exception; + } + + if (exit_code) { + switch (exit_code) { + case STATUS_DATATYPE_MISALIGNMENT: + case STATUS_ACCESS_VIOLATION: + case STATUS_IN_PAGE_ERROR: + case STATUS_INVALID_HANDLE: + case STATUS_NONCONTINUABLE_EXCEPTION: + case STATUS_INVALID_DISPOSITION: + case STATUS_ARRAY_BOUNDS_EXCEEDED: + case STATUS_STACK_OVERFLOW: + exception = Exception::Fault; + break; + case STATUS_FLOAT_DENORMAL_OPERAND: + case STATUS_FLOAT_DIVIDE_BY_ZERO: + case STATUS_FLOAT_INEXACT_RESULT: + case STATUS_FLOAT_INVALID_OPERATION: + case STATUS_FLOAT_OVERFLOW: + case STATUS_FLOAT_STACK_CHECK: + case STATUS_FLOAT_UNDERFLOW: +#ifdef STATUS_FLOAT_MULTIPLE_FAULTS + case STATUS_FLOAT_MULTIPLE_FAULTS: +#endif +#ifdef STATUS_FLOAT_MULTIPLE_TRAPS + case STATUS_FLOAT_MULTIPLE_TRAPS: +#endif + case STATUS_INTEGER_DIVIDE_BY_ZERO: + case STATUS_INTEGER_OVERFLOW: + exception = Exception::Numerical; + break; + case STATUS_CONTROL_C_EXIT: + exception = Exception::Interrupt; + break; + case STATUS_ILLEGAL_INSTRUCTION: + case STATUS_PRIVILEGED_INSTRUCTION: + exception = Exception::Illegal; + break; + default: + exception = Exception::Other; + } + } +#else + if (this->Signal) { + switch (this->Signal) { + case SIGSEGV: + exception = Exception::Fault; + break; + case SIGFPE: + exception = Exception::Numerical; + break; + case SIGINT: + exception = Exception::Interrupt; + break; + case SIGILL: + exception = Exception::Illegal; + break; + default: + exception = Exception::Other; + } + } +#endif + return exception; } std::string cmProcess::GetExitExceptionString() { - return cmsysProcess_GetExceptionString(this->Process); + std::string exception_str; +#if defined(_WIN32) + switch (this->ExitValue) { + case STATUS_CONTROL_C_EXIT: + exception_str = "User interrupt"; + break; + case STATUS_FLOAT_DENORMAL_OPERAND: + exception_str = "Floating-point exception (denormal operand)"; + break; + case STATUS_FLOAT_DIVIDE_BY_ZERO: + exception_str = "Divide-by-zero"; + break; + case STATUS_FLOAT_INEXACT_RESULT: + exception_str = "Floating-point exception (inexact result)"; + break; + case STATUS_FLOAT_INVALID_OPERATION: + exception_str = "Invalid floating-point operation"; + break; + case STATUS_FLOAT_OVERFLOW: + exception_str = "Floating-point overflow"; + break; + case STATUS_FLOAT_STACK_CHECK: + exception_str = "Floating-point stack check failed"; + break; + case STATUS_FLOAT_UNDERFLOW: + exception_str = "Floating-point underflow"; + break; +#ifdef STATUS_FLOAT_MULTIPLE_FAULTS + case STATUS_FLOAT_MULTIPLE_FAULTS: + exception_str = "Floating-point exception (multiple faults)"; + break; +#endif +#ifdef STATUS_FLOAT_MULTIPLE_TRAPS + case STATUS_FLOAT_MULTIPLE_TRAPS: + exception_str = "Floating-point exception (multiple traps)"; + break; +#endif + case STATUS_INTEGER_DIVIDE_BY_ZERO: + exception_str = "Integer divide-by-zero"; + break; + case STATUS_INTEGER_OVERFLOW: + exception_str = "Integer overflow"; + break; + + case STATUS_DATATYPE_MISALIGNMENT: + exception_str = "Datatype misalignment"; + break; + case STATUS_ACCESS_VIOLATION: + exception_str = "Access violation"; + break; + case STATUS_IN_PAGE_ERROR: + exception_str = "In-page error"; + break; + case STATUS_INVALID_HANDLE: + exception_str = "Invalid handle"; + break; + case STATUS_NONCONTINUABLE_EXCEPTION: + exception_str = "Noncontinuable exception"; + break; + case STATUS_INVALID_DISPOSITION: + exception_str = "Invalid disposition"; + break; + case STATUS_ARRAY_BOUNDS_EXCEEDED: + exception_str = "Array bounds exceeded"; + break; + case STATUS_STACK_OVERFLOW: + exception_str = "Stack overflow"; + break; + + case STATUS_ILLEGAL_INSTRUCTION: + exception_str = "Illegal instruction"; + break; + case STATUS_PRIVILEGED_INSTRUCTION: + exception_str = "Privileged instruction"; + break; + case STATUS_NO_MEMORY: + default: + char buf[1024]; + _snprintf(buf, 1024, "Exit code 0x%x\n", this->ExitValue); + exception_str.assign(buf); + } +#else + switch (this->Signal) { +#ifdef SIGSEGV + case SIGSEGV: + exception_str = "Segmentation fault"; + break; +#endif +#ifdef SIGBUS +#if !defined(SIGSEGV) || SIGBUS != SIGSEGV + case SIGBUS: + exception_str = "Bus error"; + break; +#endif +#endif +#ifdef SIGFPE + case SIGFPE: + exception_str = "Floating-point exception"; + break; +#endif +#ifdef SIGILL + case SIGILL: + exception_str = "Illegal instruction"; + break; +#endif +#ifdef SIGINT + case SIGINT: + exception_str = "User interrupt"; + break; +#endif +#ifdef SIGABRT + case SIGABRT: + exception_str = "Child aborted"; + break; +#endif +#ifdef SIGKILL + case SIGKILL: + exception_str = "Child killed"; + break; +#endif +#ifdef SIGTERM + case SIGTERM: + exception_str = "Child terminated"; + break; +#endif +#ifdef SIGHUP + case SIGHUP: + exception_str = "SIGHUP"; + break; +#endif +#ifdef SIGQUIT + case SIGQUIT: + exception_str = "SIGQUIT"; + break; +#endif +#ifdef SIGTRAP + case SIGTRAP: + exception_str = "SIGTRAP"; + break; +#endif +#ifdef SIGIOT +#if !defined(SIGABRT) || SIGIOT != SIGABRT + case SIGIOT: + exception_str = "SIGIOT"; + break; +#endif +#endif +#ifdef SIGUSR1 + case SIGUSR1: + exception_str = "SIGUSR1"; + break; +#endif +#ifdef SIGUSR2 + case SIGUSR2: + exception_str = "SIGUSR2"; + break; +#endif +#ifdef SIGPIPE + case SIGPIPE: + exception_str = "SIGPIPE"; + break; +#endif +#ifdef SIGALRM + case SIGALRM: + exception_str = "SIGALRM"; + break; +#endif +#ifdef SIGSTKFLT + case SIGSTKFLT: + exception_str = "SIGSTKFLT"; + break; +#endif +#ifdef SIGCHLD + case SIGCHLD: + exception_str = "SIGCHLD"; + break; +#elif defined(SIGCLD) + case SIGCLD: + exception_str = "SIGCLD"; + break; +#endif +#ifdef SIGCONT + case SIGCONT: + exception_str = "SIGCONT"; + break; +#endif +#ifdef SIGSTOP + case SIGSTOP: + exception_str = "SIGSTOP"; + break; +#endif +#ifdef SIGTSTP + case SIGTSTP: + exception_str = "SIGTSTP"; + break; +#endif +#ifdef SIGTTIN + case SIGTTIN: + exception_str = "SIGTTIN"; + break; +#endif +#ifdef SIGTTOU + case SIGTTOU: + exception_str = "SIGTTOU"; + break; +#endif +#ifdef SIGURG + case SIGURG: + exception_str = "SIGURG"; + break; +#endif +#ifdef SIGXCPU + case SIGXCPU: + exception_str = "SIGXCPU"; + break; +#endif +#ifdef SIGXFSZ + case SIGXFSZ: + exception_str = "SIGXFSZ"; + break; +#endif +#ifdef SIGVTALRM + case SIGVTALRM: + exception_str = "SIGVTALRM"; + break; +#endif +#ifdef SIGPROF + case SIGPROF: + exception_str = "SIGPROF"; + break; +#endif +#ifdef SIGWINCH + case SIGWINCH: + exception_str = "SIGWINCH"; + break; +#endif +#ifdef SIGPOLL + case SIGPOLL: + exception_str = "SIGPOLL"; + break; +#endif +#ifdef SIGIO +#if !defined(SIGPOLL) || SIGIO != SIGPOLL + case SIGIO: + exception_str = "SIGIO"; + break; +#endif +#endif +#ifdef SIGPWR + case SIGPWR: + exception_str = "SIGPWR"; + break; +#endif +#ifdef SIGSYS + case SIGSYS: + exception_str = "SIGSYS"; + break; +#endif +#ifdef SIGUNUSED +#if !defined(SIGSYS) || SIGUNUSED != SIGSYS + case SIGUNUSED: + exception_str = "SIGUNUSED"; + break; +#endif +#endif + default: + exception_str = "Signal "; + exception_str += std::to_string(this->Signal); + } +#endif + return exception_str; } diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h index dfb02fe..20e24b9 100644 --- a/Source/CTest/cmProcess.h +++ b/Source/CTest/cmProcess.h @@ -4,11 +4,20 @@ #define cmProcess_h #include "cmConfigure.h" // IWYU pragma: keep +#include "cmDuration.h" -#include "cmsys/Process.h" +#include "cmProcessOutput.h" +#include "cmUVHandlePtr.h" +#include "cm_uv.h" + +#include <chrono> +#include <stddef.h> +#include <stdint.h> #include <string> #include <vector> +class cmCTestRunTest; + /** \class cmProcess * \brief run a process with c++ * @@ -17,42 +26,81 @@ class cmProcess { public: - cmProcess(); + explicit cmProcess(cmCTestRunTest& runner); ~cmProcess(); const char* GetCommand() { return this->Command.c_str(); } void SetCommand(const char* command); void SetCommandArguments(std::vector<std::string> const& arg); void SetWorkingDirectory(const char* dir) { this->WorkingDirectory = dir; } - void SetTimeout(double t) { this->Timeout = t; } - void ChangeTimeout(double t); + void SetTimeout(cmDuration t) { this->Timeout = t; } + void ChangeTimeout(cmDuration t); void ResetStartTime(); // Return true if the process starts - bool StartProcess(); + bool StartProcess(uv_loop_t& loop); + + enum class State + { + Starting, + Error, + Exception, + Executing, + Exited, + Expired, + Killed, + Disowned + }; - // return the process status - int GetProcessStatus(); - // Report the status of the program - int ReportStatus(); + State GetProcessStatus(); int GetId() { return this->Id; } void SetId(int id) { this->Id = id; } int GetExitValue() { return this->ExitValue; } - double GetTotalTime() { return this->TotalTime; } - int GetExitException(); + cmDuration GetTotalTime() { return this->TotalTime; } + + enum class Exception + { + None, + Fault, + Illegal, + Interrupt, + Numerical, + Other + }; + + Exception GetExitException(); std::string GetExitExceptionString(); - /** - * Read one line of output but block for no more than timeout. - * Returns: - * cmsysProcess_Pipe_None = Process terminated and all output read - * cmsysProcess_Pipe_STDOUT = Line came from stdout or stderr - * cmsysProcess_Pipe_Timeout = Timeout expired while waiting - */ - int GetNextOutputLine(std::string& line, double timeout); private: - double Timeout; - double StartTime; - double TotalTime; - cmsysProcess* Process; + cmDuration Timeout; + std::chrono::steady_clock::time_point StartTime; + cmDuration TotalTime; + bool ReadHandleClosed = false; + bool ProcessHandleClosed = false; + + cm::uv_process_ptr Process; + cm::uv_pipe_ptr PipeReader; + cm::uv_timer_ptr Timer; + std::vector<char> Buf; + + cmCTestRunTest& Runner; + cmProcessOutput Conv; + int Signal = 0; + cmProcess::State ProcessState = cmProcess::State::Starting; + + static void OnExitCB(uv_process_t* process, int64_t exit_status, + int term_signal); + static void OnTimeoutCB(uv_timer_t* timer); + static void OnReadCB(uv_stream_t* stream, ssize_t nread, + const uv_buf_t* buf); + static void OnAllocateCB(uv_handle_t* handle, size_t suggested_size, + uv_buf_t* buf); + + void OnExit(int64_t exit_status, int term_signal); + void OnTimeout(); + void OnRead(ssize_t nread, const uv_buf_t* buf); + void OnAllocate(size_t suggested_size, uv_buf_t* buf); + + void StartTimer(); + class Buffer : public std::vector<char> { // Half-open index range of partial line already scanned. diff --git a/Source/Checks/cm_cxx14_check.cmake b/Source/Checks/cm_cxx14_check.cmake new file mode 100644 index 0000000..a78ba35 --- /dev/null +++ b/Source/Checks/cm_cxx14_check.cmake @@ -0,0 +1,36 @@ +set(CMake_CXX14_BROKEN 0) +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + if(NOT CMAKE_CXX14_STANDARD_COMPILE_OPTION) + set(CMake_CXX14_WORKS 0) + endif() + if(NOT DEFINED CMake_CXX14_WORKS) + message(STATUS "Checking if compiler supports needed C++14 constructs") + try_compile(CMake_CXX14_WORKS + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_LIST_DIR}/cm_cxx14_check.cpp + CMAKE_FLAGS -DCMAKE_CXX_STANDARD=14 + OUTPUT_VARIABLE OUTPUT + ) + if(CMake_CXX14_WORKS AND "${OUTPUT}" MATCHES "error: no member named.*gets.*in the global namespace") + set_property(CACHE CMake_CXX14_WORKS PROPERTY VALUE 0) + endif() + if(CMake_CXX14_WORKS) + message(STATUS "Checking if compiler supports needed C++14 constructs - yes") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Determining if compiler supports needed C++14 constructs passed with the following output:\n" + "${OUTPUT}\n" + "\n" + ) + else() + message(STATUS "Checking if compiler supports needed C++14 constructs - no") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Determining if compiler supports needed C++14 constructs failed with the following output:\n" + "${OUTPUT}\n" + "\n" + ) + endif() + endif() + if(NOT CMake_CXX14_WORKS) + set(CMake_CXX14_BROKEN 1) + endif() +endif() diff --git a/Source/Checks/cm_cxx14_cstdio.cpp b/Source/Checks/cm_cxx14_check.cpp index f5806a9..f5806a9 100644 --- a/Source/Checks/cm_cxx14_cstdio.cpp +++ b/Source/Checks/cm_cxx14_check.cpp diff --git a/Source/Checks/cm_cxx14_cstdio.cmake b/Source/Checks/cm_cxx14_cstdio.cmake deleted file mode 100644 index 73f7e2e..0000000 --- a/Source/Checks/cm_cxx14_cstdio.cmake +++ /dev/null @@ -1,33 +0,0 @@ -set(CMake_CXX14_CSTDIO_BROKEN 0) -if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang" AND CMAKE_CXX14_STANDARD_COMPILE_OPTION) - if(NOT DEFINED CMake_CXX14_CSTDIO_WORKS) - message(STATUS "Checking if compiler supports C++14 cstdio") - try_compile(CMake_CXX14_CSTDIO_WORKS - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_LIST_DIR}/cm_cxx14_cstdio.cpp - CMAKE_FLAGS -DCMAKE_CXX_STANDARD=14 - OUTPUT_VARIABLE OUTPUT - ) - if(CMake_CXX14_CSTDIO_WORKS AND "${OUTPUT}" MATCHES "error: no member named.*gets.*in the global namespace") - set_property(CACHE CMake_CXX14_CSTDIO_WORKS PROPERTY VALUE 0) - endif() - if(CMake_CXX14_CSTDIO_WORKS) - message(STATUS "Checking if compiler supports C++14 cstdio - yes") - file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log - "Determining if compiler supports C++14 cstdio passed with the following output:\n" - "${OUTPUT}\n" - "\n" - ) - else() - message(STATUS "Checking if compiler supports C++14 cstdio - no") - file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log - "Determining if compiler supports C++14 cstdio failed with the following output:\n" - "${OUTPUT}\n" - "\n" - ) - endif() - endif() - if(NOT CMake_CXX14_CSTDIO_WORKS) - set(CMake_CXX14_CSTDIO_BROKEN 1) - endif() -endif() diff --git a/Source/Checks/cm_cxx17_check.cmake b/Source/Checks/cm_cxx17_check.cmake new file mode 100644 index 0000000..83d3971 --- /dev/null +++ b/Source/Checks/cm_cxx17_check.cmake @@ -0,0 +1,36 @@ +set(CMake_CXX17_BROKEN 0) +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + if(NOT CMAKE_CXX17_STANDARD_COMPILE_OPTION) + set(CMake_CXX17_WORKS 0) + endif() + if(NOT DEFINED CMake_CXX17_WORKS) + message(STATUS "Checking if compiler supports needed C++17 constructs") + try_compile(CMake_CXX17_WORKS + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_LIST_DIR}/cm_cxx17_check.cpp + CMAKE_FLAGS -DCMAKE_CXX_STANDARD=17 + OUTPUT_VARIABLE OUTPUT + ) + if(CMake_CXX17_WORKS AND "${OUTPUT}" MATCHES "error: no member named.*gets.*in the global namespace") + set_property(CACHE CMake_CXX17_WORKS PROPERTY VALUE 0) + endif() + if(CMake_CXX17_WORKS) + message(STATUS "Checking if compiler supports needed C++17 constructs - yes") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Determining if compiler supports needed C++17 constructs passed with the following output:\n" + "${OUTPUT}\n" + "\n" + ) + else() + message(STATUS "Checking if compiler supports needed C++17 constructs - no") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Determining if compiler supports needed C++17 constructs failed with the following output:\n" + "${OUTPUT}\n" + "\n" + ) + endif() + endif() + if(NOT CMake_CXX17_WORKS) + set(CMake_CXX17_BROKEN 1) + endif() +endif() diff --git a/Source/Checks/cm_cxx17_check.cpp b/Source/Checks/cm_cxx17_check.cpp new file mode 100644 index 0000000..2cbf1d5 --- /dev/null +++ b/Source/Checks/cm_cxx17_check.cpp @@ -0,0 +1,7 @@ +#include <cstdio> +#include <unordered_map> + +int main() +{ + return 0; +} 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/CursesDialog/CMakeLists.txt b/Source/CursesDialog/CMakeLists.txt index 6023c83..c51b0dd 100644 --- a/Source/CursesDialog/CMakeLists.txt +++ b/Source/CursesDialog/CMakeLists.txt @@ -2,19 +2,19 @@ # file Copyright.txt or https://cmake.org/licensing for details. set( CURSES_SRCS - CursesDialog/cmCursesOptionsWidget - CursesDialog/cmCursesBoolWidget - CursesDialog/cmCursesCacheEntryComposite - CursesDialog/cmCursesDummyWidget - CursesDialog/cmCursesFilePathWidget - CursesDialog/cmCursesForm - CursesDialog/cmCursesLabelWidget - CursesDialog/cmCursesLongMessageForm - CursesDialog/cmCursesMainForm - CursesDialog/cmCursesPathWidget - CursesDialog/cmCursesStringWidget - CursesDialog/cmCursesWidget - CursesDialog/ccmake + CursesDialog/cmCursesOptionsWidget.cxx + CursesDialog/cmCursesBoolWidget.cxx + CursesDialog/cmCursesCacheEntryComposite.cxx + CursesDialog/cmCursesDummyWidget.cxx + CursesDialog/cmCursesFilePathWidget.cxx + CursesDialog/cmCursesForm.cxx + CursesDialog/cmCursesLabelWidget.cxx + CursesDialog/cmCursesLongMessageForm.cxx + CursesDialog/cmCursesMainForm.cxx + CursesDialog/cmCursesPathWidget.cxx + CursesDialog/cmCursesStringWidget.cxx + CursesDialog/cmCursesWidget.cxx + CursesDialog/ccmake.cxx ) include_directories(${CURSES_INCLUDE_PATH}) diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx index 97d5579..17cf628 100644 --- a/Source/CursesDialog/ccmake.cxx +++ b/Source/CursesDialog/ccmake.cxx @@ -75,6 +75,7 @@ int main(int argc, char const* const* argv) argc = encoding_args.argc(); argv = encoding_args.argv(); + cmSystemTools::InitializeLibUV(); cmSystemTools::FindCMakeResources(argv[0]); cmDocumentation doc; doc.addCMakeStandardDocSections(); 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/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt index b38797b..330b747 100644 --- a/Source/QtDialog/CMakeLists.txt +++ b/Source/QtDialog/CMakeLists.txt @@ -40,7 +40,7 @@ if (Qt5Widgets_FOUND) endif() # We need to install platform plugin and add qt.conf for Qt5 on Mac and Windows. - # FIXME: This should be part of Qt5 CMake scripts, but unfortunatelly + # FIXME: This should be part of Qt5 CMake scripts, but unfortunately # Qt5 support is missing there. if(CMake_INSTALL_DEPENDENCIES AND (APPLE OR WIN32)) macro(install_qt5_plugin _qt_plugin_name _qt_plugins_var) @@ -166,6 +166,10 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) add_executable(cmake-gui WIN32 MACOSX_BUNDLE ${SRCS} ${MANIFEST_FILE}) target_link_libraries(cmake-gui CMakeLib ${QT_QTMAIN_LIBRARY} ${CMake_QT_LIBRARIES}) +if(WIN32) + target_sources(cmake-gui PRIVATE $<TARGET_OBJECTS:CMakeVersion>) +endif() + # cmake-gui has not been updated for `include-what-you-use`. # Block the tool until this is done. set_target_properties(cmake-gui PROPERTIES diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx index bfd43cf..193f4d3 100644 --- a/Source/QtDialog/CMakeSetup.cxx +++ b/Source/QtDialog/CMakeSetup.cxx @@ -55,6 +55,7 @@ int main(int argc, char** argv) int argc2 = encoding_args.argc(); char const* const* argv2 = encoding_args.argv(); + cmSystemTools::InitializeLibUV(); cmSystemTools::FindCMakeResources(argv2[0]); // check docs first so that X is not need to get docs // do docs, if args were given 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..a84429b 100644 --- a/Source/QtDialog/QCMake.cxx +++ b/Source/QtDialog/QCMake.cxx @@ -39,15 +39,6 @@ QCMake::QCMake(QObject* p) std::vector<cmake::GeneratorInfo>::const_iterator it; for (it = generators.begin(); it != generators.end(); ++it) { - // Skip the generator "KDevelop3", since there is also - // "KDevelop3 - Unix Makefiles", which is the full and official name. - // The short name is actually only still there since this was the name - // in CMake 2.4, to keep "command line argument compatibility", but - // this is not necessary in the GUI. - if (it->name == "KDevelop3") { - continue; - } - this->AvailableGenerators.push_back(*it); } } @@ -115,6 +106,8 @@ void QCMake::setBinaryDirectory(const QString& _dir) if (toolset) { this->setToolset(QString::fromLocal8Bit(toolset)); } + + checkOpenPossible(); } } @@ -183,6 +176,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 +463,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/QtDialog/RegexExplorer.cxx b/Source/QtDialog/RegexExplorer.cxx index abed70e..cb67f85 100644 --- a/Source/QtDialog/RegexExplorer.cxx +++ b/Source/QtDialog/RegexExplorer.cxx @@ -8,7 +8,7 @@ RegexExplorer::RegexExplorer(QWidget* p) { this->setupUi(this); - for (int i = 1; i < cmsys::RegularExpression::NSUBEXP; ++i) { + for (int i = 1; i < cmsys::RegularExpressionMatch::NSUBEXP; ++i) { matchNumber->addItem(QString("Match %1").arg(QString::number(i)), QVariant(i)); } @@ -105,7 +105,7 @@ void RegexExplorer::on_matchNumber_currentIndexChanged(int index) QVariant itemData = matchNumber->itemData(index); int idx = itemData.toInt(); - if (idx < 1 || idx >= cmsys::RegularExpression::NSUBEXP) { + if (idx < 1 || idx >= cmsys::RegularExpressionMatch::NSUBEXP) { return; } diff --git a/Source/bindexplib.cxx b/Source/bindexplib.cxx index 2eb47f3..9ec9624 100644 --- a/Source/bindexplib.cxx +++ b/Source/bindexplib.cxx @@ -31,7 +31,7 @@ * Extension (Axel 2006-03-15) * As soon as an object file contains an /EXPORT directive (which * is generated by the compiler when a symbol is declared as - * declspec(dllexport)) no to-be-exported symbols are printed, + * __declspec(dllexport) no to-be-exported symbols are printed, * as the linker will see these directives, and if those directives * are present we only export selectively (i.e. we trust the * programmer). @@ -50,12 +50,12 @@ * * It created a wrong EXPORTS for the global pointers and constants. * The Section Header has been involved to discover the missing information -* Now the pointers are correctly supplied supplied with "DATA" descriptor +* Now the pointers are correctly supplied with "DATA" descriptor * the constants with no extra descriptor. * * Corrections (Valery Fine 16/09/96): * -* It didn't work for C++ code with global variables and class definitons +* It didn't work for C++ code with global variables and class definitions * The DumpExternalObject function has been introduced to generate .DEF file * * Author: Valery Fine 16/09/96 (E-mail: fine@vxcern.cern.ch) @@ -68,8 +68,20 @@ #include <iostream> #include <windows.h> +#ifndef IMAGE_FILE_MACHINE_ARM +#define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM Little-Endian +#endif + +#ifndef IMAGE_FILE_MACHINE_THUMB +#define IMAGE_FILE_MACHINE_THUMB 0x01c2 // ARM Thumb/Thumb-2 Little-Endian +#endif + #ifndef IMAGE_FILE_MACHINE_ARMNT -#define IMAGE_FILE_MACHINE_ARMNT 0x01c4 +#define IMAGE_FILE_MACHINE_ARMNT 0x01c4 // ARM Thumb-2 Little-Endian +#endif + +#ifndef IMAGE_FILE_MACHINE_ARM64 +#define IMAGE_FILE_MACHINE_ARM64 0xaa64 // ARM64 Little-Endian #endif typedef struct cmANON_OBJECT_HEADER_BIGOBJ @@ -294,7 +306,6 @@ bool DumpFile(const char* filename, std::set<std::string>& symbols, HANDLE hFile; HANDLE hFileMapping; LPVOID lpFileBase; - PIMAGE_DOS_HEADER dosHeader; hFile = CreateFileW(cmsys::Encoding::ToWide(filename).c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, @@ -320,36 +331,42 @@ bool DumpFile(const char* filename, std::set<std::string>& symbols, return false; } - dosHeader = (PIMAGE_DOS_HEADER)lpFileBase; + const PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)lpFileBase; if (dosHeader->e_magic == IMAGE_DOS_SIGNATURE) { fprintf(stderr, "File is an executable. I don't dump those.\n"); return false; - } - /* Does it look like a COFF OBJ file??? */ - else if (((dosHeader->e_magic == IMAGE_FILE_MACHINE_I386) || - (dosHeader->e_magic == IMAGE_FILE_MACHINE_AMD64) || - (dosHeader->e_magic == IMAGE_FILE_MACHINE_ARMNT)) && - (dosHeader->e_sp == 0)) { - /* - * The two tests above aren't what they look like. They're - * really checking for IMAGE_FILE_HEADER.Machine == i386 (0x14C) - * and IMAGE_FILE_HEADER.SizeOfOptionalHeader == 0; - */ - DumpSymbols<IMAGE_FILE_HEADER, IMAGE_SYMBOL> symbolDumper( - (PIMAGE_FILE_HEADER)lpFileBase, symbols, dataSymbols, - (dosHeader->e_magic == IMAGE_FILE_MACHINE_I386)); - symbolDumper.DumpObjFile(); } else { - // check for /bigobj format - cmANON_OBJECT_HEADER_BIGOBJ* h = (cmANON_OBJECT_HEADER_BIGOBJ*)lpFileBase; - if (h->Sig1 == 0x0 && h->Sig2 == 0xffff) { - DumpSymbols<cmANON_OBJECT_HEADER_BIGOBJ, cmIMAGE_SYMBOL_EX> symbolDumper( - (cmANON_OBJECT_HEADER_BIGOBJ*)lpFileBase, symbols, dataSymbols, - (h->Machine == IMAGE_FILE_MACHINE_I386)); + const PIMAGE_FILE_HEADER imageHeader = (PIMAGE_FILE_HEADER)lpFileBase; + /* Does it look like a COFF OBJ file??? */ + if (((imageHeader->Machine == IMAGE_FILE_MACHINE_I386) || + (imageHeader->Machine == IMAGE_FILE_MACHINE_AMD64) || + (imageHeader->Machine == IMAGE_FILE_MACHINE_ARM) || + (imageHeader->Machine == IMAGE_FILE_MACHINE_ARMNT) || + (imageHeader->Machine == IMAGE_FILE_MACHINE_ARM64)) && + (imageHeader->Characteristics == 0)) { + /* + * The tests above are checking for IMAGE_FILE_HEADER.Machine + * if it contains supported machine formats (currently ARM and x86) + * and IMAGE_FILE_HEADER.Characteristics == 0 indicating that + * this is not linked COFF OBJ file; + */ + DumpSymbols<IMAGE_FILE_HEADER, IMAGE_SYMBOL> symbolDumper( + (PIMAGE_FILE_HEADER)lpFileBase, symbols, dataSymbols, + (imageHeader->Machine == IMAGE_FILE_MACHINE_I386)); symbolDumper.DumpObjFile(); } else { - printf("unrecognized file format in '%s'\n", filename); - return false; + // check for /bigobj format + cmANON_OBJECT_HEADER_BIGOBJ* h = + (cmANON_OBJECT_HEADER_BIGOBJ*)lpFileBase; + if (h->Sig1 == 0x0 && h->Sig2 == 0xffff) { + DumpSymbols<cmANON_OBJECT_HEADER_BIGOBJ, cmIMAGE_SYMBOL_EX> + symbolDumper((cmANON_OBJECT_HEADER_BIGOBJ*)lpFileBase, symbols, + dataSymbols, (h->Machine == IMAGE_FILE_MACHINE_I386)); + symbolDumper.DumpObjFile(); + } else { + printf("unrecognized file format in '%s'\n", filename); + return false; + } } } UnmapViewOfFile(lpFileBase); diff --git a/Source/cmAddCompileOptionsCommand.cxx b/Source/cmAddCompileOptionsCommand.cxx index c37fd9a..412fb38 100644 --- a/Source/cmAddCompileOptionsCommand.cxx +++ b/Source/cmAddCompileOptionsCommand.cxx @@ -14,7 +14,7 @@ bool cmAddCompileOptionsCommand::InitialPass( } for (std::string const& i : args) { - this->Makefile->AddCompileOption(i.c_str()); + this->Makefile->AddCompileOption(i); } return true; } diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx index 7fed52d..1e3faef 100644 --- a/Source/cmAddCustomCommandCommand.cxx +++ b/Source/cmAddCustomCommandCommand.cxx @@ -3,6 +3,8 @@ #include "cmAddCustomCommandCommand.h" #include <sstream> +#include <unordered_set> +#include <utility> #include "cmCustomCommand.h" #include "cmCustomCommandLines.h" @@ -68,57 +70,106 @@ bool cmAddCustomCommandCommand::InitialPass( tdoing doing = doing_nothing; +#define MAKE_STATIC_KEYWORD(KEYWORD) \ + static const std::string key##KEYWORD = #KEYWORD + MAKE_STATIC_KEYWORD(APPEND); + MAKE_STATIC_KEYWORD(ARGS); + MAKE_STATIC_KEYWORD(BYPRODUCTS); + MAKE_STATIC_KEYWORD(COMMAND); + MAKE_STATIC_KEYWORD(COMMAND_EXPAND_LISTS); + MAKE_STATIC_KEYWORD(COMMENT); + MAKE_STATIC_KEYWORD(DEPENDS); + MAKE_STATIC_KEYWORD(DEPFILE); + MAKE_STATIC_KEYWORD(IMPLICIT_DEPENDS); + MAKE_STATIC_KEYWORD(MAIN_DEPENDENCY); + MAKE_STATIC_KEYWORD(OUTPUT); + MAKE_STATIC_KEYWORD(OUTPUTS); + MAKE_STATIC_KEYWORD(POST_BUILD); + MAKE_STATIC_KEYWORD(PRE_BUILD); + MAKE_STATIC_KEYWORD(PRE_LINK); + MAKE_STATIC_KEYWORD(SOURCE); + MAKE_STATIC_KEYWORD(TARGET); + MAKE_STATIC_KEYWORD(USES_TERMINAL); + MAKE_STATIC_KEYWORD(VERBATIM); + MAKE_STATIC_KEYWORD(WORKING_DIRECTORY); +#undef MAKE_STATIC_KEYWORD + static std::unordered_set<std::string> keywords; + if (keywords.empty()) { + keywords.insert(keyAPPEND); + keywords.insert(keyARGS); + keywords.insert(keyBYPRODUCTS); + keywords.insert(keyCOMMAND); + keywords.insert(keyCOMMAND_EXPAND_LISTS); + keywords.insert(keyCOMMENT); + keywords.insert(keyDEPENDS); + keywords.insert(keyDEPFILE); + keywords.insert(keyIMPLICIT_DEPENDS); + keywords.insert(keyMAIN_DEPENDENCY); + keywords.insert(keyOUTPUT); + keywords.insert(keyOUTPUTS); + keywords.insert(keyPOST_BUILD); + keywords.insert(keyPRE_BUILD); + keywords.insert(keyPRE_LINK); + keywords.insert(keySOURCE); + keywords.insert(keyTARGET); + keywords.insert(keyUSES_TERMINAL); + keywords.insert(keyVERBATIM); + keywords.insert(keyWORKING_DIRECTORY); + } + for (std::string const& copy : args) { - if (copy == "SOURCE") { - doing = doing_source; - } else if (copy == "COMMAND") { - doing = doing_command; + if (keywords.count(copy)) { + if (copy == keySOURCE) { + doing = doing_source; + } else if (copy == keyCOMMAND) { + doing = doing_command; - // Save the current command before starting the next command. - if (!currentLine.empty()) { - commandLines.push_back(currentLine); - currentLine.clear(); - } - } else if (copy == "PRE_BUILD") { - cctype = cmTarget::PRE_BUILD; - } else if (copy == "PRE_LINK") { - cctype = cmTarget::PRE_LINK; - } else if (copy == "POST_BUILD") { - cctype = cmTarget::POST_BUILD; - } else if (copy == "VERBATIM") { - verbatim = true; - } else if (copy == "APPEND") { - append = true; - } else if (copy == "USES_TERMINAL") { - uses_terminal = true; - } else if (copy == "COMMAND_EXPAND_LISTS") { - command_expand_lists = true; - } else if (copy == "TARGET") { - doing = doing_target; - } else if (copy == "ARGS") { - // Ignore this old keyword. - } else if (copy == "DEPENDS") { - doing = doing_depends; - } else if (copy == "OUTPUTS") { - doing = doing_outputs; - } else if (copy == "OUTPUT") { - doing = doing_output; - } else if (copy == "BYPRODUCTS") { - doing = doing_byproducts; - } else if (copy == "WORKING_DIRECTORY") { - doing = doing_working_directory; - } else if (copy == "MAIN_DEPENDENCY") { - doing = doing_main_dependency; - } else if (copy == "IMPLICIT_DEPENDS") { - doing = doing_implicit_depends_lang; - } else if (copy == "COMMENT") { - doing = doing_comment; - } else if (copy == "DEPFILE") { - doing = doing_depfile; - if (this->Makefile->GetGlobalGenerator()->GetName() != "Ninja") { - this->SetError("Option DEPFILE not supported by " + - this->Makefile->GetGlobalGenerator()->GetName()); - return false; + // Save the current command before starting the next command. + if (!currentLine.empty()) { + commandLines.push_back(currentLine); + currentLine.clear(); + } + } else if (copy == keyPRE_BUILD) { + cctype = cmTarget::PRE_BUILD; + } else if (copy == keyPRE_LINK) { + cctype = cmTarget::PRE_LINK; + } else if (copy == keyPOST_BUILD) { + cctype = cmTarget::POST_BUILD; + } else if (copy == keyVERBATIM) { + verbatim = true; + } else if (copy == keyAPPEND) { + append = true; + } else if (copy == keyUSES_TERMINAL) { + uses_terminal = true; + } else if (copy == keyCOMMAND_EXPAND_LISTS) { + command_expand_lists = true; + } else if (copy == keyTARGET) { + doing = doing_target; + } else if (copy == keyARGS) { + // Ignore this old keyword. + } else if (copy == keyDEPENDS) { + doing = doing_depends; + } else if (copy == keyOUTPUTS) { + doing = doing_outputs; + } else if (copy == keyOUTPUT) { + doing = doing_output; + } else if (copy == keyBYPRODUCTS) { + doing = doing_byproducts; + } else if (copy == keyWORKING_DIRECTORY) { + doing = doing_working_directory; + } else if (copy == keyMAIN_DEPENDENCY) { + doing = doing_main_dependency; + } else if (copy == keyIMPLICIT_DEPENDS) { + doing = doing_implicit_depends_lang; + } else if (copy == keyCOMMENT) { + doing = doing_comment; + } else if (copy == keyDEPFILE) { + doing = doing_depfile; + if (this->Makefile->GetGlobalGenerator()->GetName() != "Ninja") { + this->SetError("Option DEPFILE not supported by " + + this->Makefile->GetGlobalGenerator()->GetName()); + return false; + } } } else { std::string filename; @@ -126,7 +177,7 @@ bool cmAddCustomCommandCommand::InitialPass( case doing_output: case doing_outputs: case doing_byproducts: - if (!cmSystemTools::FileIsFullPath(copy.c_str())) { + if (!cmSystemTools::FileIsFullPath(copy)) { // This is an output to be generated, so it should be // under the build tree. CMake 2.4 placed this under the // source tree. However the only case that this change @@ -153,7 +204,7 @@ bool cmAddCustomCommandCommand::InitialPass( break; } - if (cmSystemTools::FileIsFullPath(filename.c_str())) { + if (cmSystemTools::FileIsFullPath(filename)) { filename = cmSystemTools::CollapseFullPath(filename); } switch (doing) { @@ -184,9 +235,7 @@ bool cmAddCustomCommandCommand::InitialPass( depends.push_back(dep); // Add the implicit dependency language and file. - cmCustomCommand::ImplicitDependsPair entry(implicit_depends_lang, - dep); - implicit_depends.push_back(entry); + implicit_depends.emplace_back(implicit_depends_lang, dep); // Switch back to looking for a language. doing = doing_implicit_depends_lang; @@ -200,7 +249,7 @@ bool cmAddCustomCommandCommand::InitialPass( case doing_depends: { std::string dep = copy; cmSystemTools::ConvertToUnixSlashes(dep); - depends.push_back(dep); + depends.push_back(std::move(dep)); } break; case doing_outputs: outputs.push_back(filename); @@ -356,7 +405,7 @@ bool cmAddCustomCommandCommand::CheckOutputs( for (std::string const& o : outputs) { // Make sure the file will not be generated into the source // directory during an out of source build. - if (!this->Makefile->CanIWriteThisFile(o.c_str())) { + if (!this->Makefile->CanIWriteThisFile(o)) { std::string e = "attempted to have a file \"" + o + "\" in a source directory as an output of custom command."; this->SetError(e); diff --git a/Source/cmAddCustomTargetCommand.cxx b/Source/cmAddCustomTargetCommand.cxx index a8d5b2e..4655f58 100644 --- a/Source/cmAddCustomTargetCommand.cxx +++ b/Source/cmAddCustomTargetCommand.cxx @@ -3,12 +3,13 @@ #include "cmAddCustomTargetCommand.h" #include <sstream> +#include <utility> #include "cmCustomCommandLines.h" #include "cmGeneratorExpression.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" -#include "cmPolicies.h" +#include "cmStateTypes.h" #include "cmSystemTools.h" #include "cmTarget.h" #include "cmake.h" @@ -116,7 +117,7 @@ bool cmAddCustomTargetCommand::InitialPass( break; case doing_byproducts: { std::string filename; - if (!cmSystemTools::FileIsFullPath(copy.c_str())) { + if (!cmSystemTools::FileIsFullPath(copy)) { filename = this->Makefile->GetCurrentBinaryDirectory(); filename += "/"; } @@ -127,7 +128,7 @@ bool cmAddCustomTargetCommand::InitialPass( case doing_depends: { std::string dep = copy; cmSystemTools::ConvertToUnixSlashes(dep); - depends.push_back(dep); + depends.push_back(std::move(dep)); } break; case doing_comment: comment_buffer = copy; @@ -160,35 +161,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 +210,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/cmAddDefinitionsCommand.cxx b/Source/cmAddDefinitionsCommand.cxx index 261fb5b..62e57a3 100644 --- a/Source/cmAddDefinitionsCommand.cxx +++ b/Source/cmAddDefinitionsCommand.cxx @@ -16,7 +16,7 @@ bool cmAddDefinitionsCommand::InitialPass(std::vector<std::string> const& args, } for (std::string const& i : args) { - this->Makefile->AddDefineFlag(i.c_str()); + this->Makefile->AddDefineFlag(i); } return true; } diff --git a/Source/cmAddExecutableCommand.cxx b/Source/cmAddExecutableCommand.cxx index 1d0376f..5685fdf 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. @@ -127,7 +99,7 @@ bool cmAddExecutableCommand::InitialPass(std::vector<std::string> const& args, return false; } - const char* aliasedName = s->c_str(); + std::string const& aliasedName = *s; if (this->Makefile->IsAlias(aliasedName)) { std::ostringstream e; e << "cannot create ALIAS target \"" << exename << "\" because target \"" @@ -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,15 +162,9 @@ 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); + this->Makefile->AddExecutable(exename, srclists, excludeFromAll); if (use_win32) { tgt->SetProperty("WIN32_EXECUTABLE", "ON"); } diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx index ebf1763..1278232 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) { @@ -226,7 +198,7 @@ bool cmAddLibraryCommand::InitialPass(std::vector<std::string> const& args, return false; } - const char* aliasedName = s->c_str(); + std::string const& aliasedName = *s; if (this->Makefile->IsAlias(aliasedName)) { std::ostringstream e; e << "cannot create ALIAS target \"" << libName << "\" because target \"" @@ -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/cmAddSubDirectoryCommand.cxx b/Source/cmAddSubDirectoryCommand.cxx index 1727ca5..f673c72 100644 --- a/Source/cmAddSubDirectoryCommand.cxx +++ b/Source/cmAddSubDirectoryCommand.cxx @@ -44,7 +44,7 @@ bool cmAddSubDirectoryCommand::InitialPass( // Compute the full path to the specified source directory. // Interpret a relative path with respect to the current source directory. std::string srcPath; - if (cmSystemTools::FileIsFullPath(srcArg.c_str())) { + if (cmSystemTools::FileIsFullPath(srcArg)) { srcPath = srcArg; } else { srcPath = this->Makefile->GetCurrentSourceDirectory(); @@ -94,7 +94,7 @@ bool cmAddSubDirectoryCommand::InitialPass( } else { // Use the binary directory specified. // Interpret a relative path with respect to the current binary directory. - if (cmSystemTools::FileIsFullPath(binArg.c_str())) { + if (cmSystemTools::FileIsFullPath(binArg)) { binPath = binArg; } else { binPath = this->Makefile->GetCurrentBinaryDirectory(); 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..1f9f580 100644 --- a/Source/cmAuxSourceDirectoryCommand.cxx +++ b/Source/cmAuxSourceDirectoryCommand.cxx @@ -26,7 +26,7 @@ bool cmAuxSourceDirectoryCommand::InitialPass( std::string sourceListValue; std::string const& templateDirectory = args[0]; std::string tdir; - if (!cmSystemTools::FileIsFullPath(templateDirectory.c_str())) { + if (!cmSystemTools::FileIsFullPath(templateDirectory)) { tdir = this->Makefile->GetCurrentSourceDirectory(); tdir += "/"; tdir += templateDirectory; @@ -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; @@ -65,7 +63,7 @@ bool cmAuxSourceDirectoryCommand::InitialPass( // depends can be done cmSourceFile* sf = this->Makefile->GetOrCreateSource(fullname); sf->SetProperty("ABSTRACT", "0"); - files.push_back(fullname); + files.push_back(std::move(fullname)); } } } 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..1ec76ac 100644 --- a/Source/cmCPluginAPI.cxx +++ b/Source/cmCPluginAPI.cxx @@ -108,12 +108,12 @@ const char* CCONV cmGetProjectName(void* arg) const char* CCONV cmGetHomeDirectory(void* arg) { cmMakefile* mf = static_cast<cmMakefile*>(arg); - return mf->GetHomeDirectory(); + return mf->GetHomeDirectory().c_str(); } const char* CCONV cmGetHomeOutputDirectory(void* arg) { cmMakefile* mf = static_cast<cmMakefile*>(arg); - return mf->GetHomeOutputDirectory(); + return mf->GetHomeOutputDirectory().c_str(); } const char* CCONV cmGetStartDirectory(void* arg) { @@ -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..3fccc38 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> @@ -183,7 +184,7 @@ int cmCTest::HTTPRequest(std::string url, HTTPMethod method, ::curl_easy_setopt(curl, CURLOPT_POSTFIELDS, fields.c_str()); break; case cmCTest::HTTP_PUT: - if (!cmSystemTools::FileExists(putFile.c_str())) { + if (!cmSystemTools::FileExists(putFile)) { response = "Error: File "; response += putFile + " does not exist.\n"; return -1; @@ -259,7 +260,6 @@ cmCTest::cmCTest() this->TestLoad = 0; this->SubmitIndex = 0; this->Failover = false; - this->BatchJobs = false; this->ForceNewCTestProcess = false; this->TomorrowTag = false; this->Verbose = false; @@ -277,14 +277,10 @@ cmCTest::cmCTest() this->TestModel = cmCTest::EXPERIMENTAL; this->MaxTestNameWidth = 30; this->InteractiveDebugMode = true; - this->TimeOut = 0; - this->GlobalTimeout = 0; - this->LastStopTimeout = 24 * 60 * 60; + this->TimeOut = cmDuration::zero(); + this->GlobalTimeout = cmDuration::zero(); this->CompressXMLFiles = false; - this->CTestConfigFile.clear(); this->ScheduleType.clear(); - this->StopTime.clear(); - this->NextDayStopTime = false; this->OutputLogFile = nullptr; this->OutputLogFileLastTag = -1; this->SuppressUpdatingCTestConfiguration = false; @@ -433,7 +429,7 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command) // Verify "Testing" directory exists: // std::string testingDir = this->BinaryDir + "/Testing"; - if (cmSystemTools::FileExists(testingDir.c_str())) { + if (cmSystemTools::FileExists(testingDir)) { if (!cmSystemTools::FileIsDirectory(testingDir)) { cmCTestLog(this, ERROR_MESSAGE, "File " << testingDir @@ -442,7 +438,7 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command) return 0; } } else { - if (!cmSystemTools::MakeDirectory(testingDir.c_str())) { + if (!cmSystemTools::MakeDirectory(testingDir)) { cmCTestLog(this, ERROR_MESSAGE, "Cannot create directory " << testingDir << std::endl); return 0; @@ -560,9 +556,9 @@ bool cmCTest::InitializeFromCommand(cmCTestStartCommand* command) bld_dir_fname += "/CTestConfig.cmake"; cmSystemTools::ConvertToUnixSlashes(bld_dir_fname); - if (cmSystemTools::FileExists(bld_dir_fname.c_str())) { + if (cmSystemTools::FileExists(bld_dir_fname)) { fname = bld_dir_fname; - } else if (cmSystemTools::FileExists(src_dir_fname.c_str())) { + } else if (cmSystemTools::FileExists(src_dir_fname)) { fname = src_dir_fname; } @@ -622,16 +618,13 @@ 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)) { + fileName = this->BinaryDir + "/DartConfiguration.tcl"; } cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "UpdateCTestConfiguration from :" << fileName << "\n"); - if (!cmSystemTools::FileExists(fileName.c_str())) { + if (!cmSystemTools::FileExists(fileName)) { // No need to exit if we are not producing XML if (this->ProduceXML) { cmCTestLog(this, ERROR_MESSAGE, "Cannot find file: " << fileName @@ -681,7 +674,8 @@ bool cmCTest::UpdateCTestConfiguration() this->BinaryDir = this->GetCTestConfiguration("BuildDirectory"); cmSystemTools::ChangeDirectory(this->BinaryDir); } - this->TimeOut = atoi(this->GetCTestConfiguration("TimeOut").c_str()); + this->TimeOut = + std::chrono::seconds(atoi(this->GetCTestConfiguration("TimeOut").c_str())); std::string const& testLoad = this->GetCTestConfiguration("TestLoad"); if (!testLoad.empty()) { unsigned long load; @@ -747,7 +741,7 @@ bool cmCTest::OpenOutputFile(const std::string& path, const std::string& name, if (!path.empty()) { testingDir += "/" + path; } - if (cmSystemTools::FileExists(testingDir.c_str())) { + if (cmSystemTools::FileExists(testingDir)) { if (!cmSystemTools::FileIsDirectory(testingDir)) { cmCTestLog(this, ERROR_MESSAGE, "File " << testingDir << " is in the place of the testing directory" @@ -755,7 +749,7 @@ bool cmCTest::OpenOutputFile(const std::string& path, const std::string& name, return false; } } else { - if (!cmSystemTools::MakeDirectory(testingDir.c_str())) { + if (!cmSystemTools::MakeDirectory(testingDir)) { cmCTestLog(this, ERROR_MESSAGE, "Cannot create directory " << testingDir << std::endl); return false; @@ -796,7 +790,7 @@ bool cmCTest::CTestFileExists(const std::string& filename) { std::string testingDir = this->BinaryDir + "/Testing/" + this->CurrentTag + "/" + filename; - return cmSystemTools::FileExists(testingDir.c_str()); + return cmSystemTools::FileExists(testingDir); } cmCTestGenericHandler* cmCTest::GetInitializedHandler(const char* handler) @@ -839,7 +833,8 @@ int cmCTest::ProcessSteps() for (Part p = PartStart; notest && p != PartCount; p = Part(p + 1)) { notest = !this->Parts[p]; } - if (this->Parts[PartUpdate] && (this->GetRemainingTimeAllowed() - 120 > 0)) { + if (this->Parts[PartUpdate] && + (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) { cmCTestGenericHandler* uphandler = this->GetHandler("update"); uphandler->SetPersistentOption( "SourceDirectory", @@ -853,33 +848,34 @@ int cmCTest::ProcessSteps() return 0; } if (this->Parts[PartConfigure] && - (this->GetRemainingTimeAllowed() - 120 > 0)) { + (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) { if (this->GetHandler("configure")->ProcessHandler() < 0) { res |= cmCTest::CONFIGURE_ERRORS; } } - if (this->Parts[PartBuild] && (this->GetRemainingTimeAllowed() - 120 > 0)) { + if (this->Parts[PartBuild] && + (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) { this->UpdateCTestConfiguration(); if (this->GetHandler("build")->ProcessHandler() < 0) { res |= cmCTest::BUILD_ERRORS; } } if ((this->Parts[PartTest] || notest) && - (this->GetRemainingTimeAllowed() - 120 > 0)) { + (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) { this->UpdateCTestConfiguration(); if (this->GetHandler("test")->ProcessHandler() < 0) { res |= cmCTest::TEST_ERRORS; } } if (this->Parts[PartCoverage] && - (this->GetRemainingTimeAllowed() - 120 > 0)) { + (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) { this->UpdateCTestConfiguration(); if (this->GetHandler("coverage")->ProcessHandler() < 0) { res |= cmCTest::COVERAGE_ERRORS; } } if (this->Parts[PartMemCheck] && - (this->GetRemainingTimeAllowed() - 120 > 0)) { + (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) { this->UpdateCTestConfiguration(); if (this->GetHandler("memcheck")->ProcessHandler() < 0) { res |= cmCTest::MEMORY_ERRORS; @@ -894,7 +890,7 @@ int cmCTest::ProcessSteps() for (kk = 0; kk < d.GetNumberOfFiles(); kk++) { const char* file = d.GetFile(kk); std::string fullname = notes_dir + "/" + file; - if (cmSystemTools::FileExists(fullname.c_str()) && + if (cmSystemTools::FileExists(fullname) && !cmSystemTools::FileIsDirectory(fullname)) { if (!this->NotesFiles.empty()) { this->NotesFiles += ";"; @@ -943,10 +939,10 @@ int cmCTest::GetTestModelFromString(const char* str) return cmCTest::EXPERIMENTAL; } std::string rstr = cmSystemTools::LowerCase(str); - if (cmHasLiteralPrefix(rstr.c_str(), "cont")) { + if (cmHasLiteralPrefix(rstr, "cont")) { return cmCTest::CONTINUOUS; } - if (cmHasLiteralPrefix(rstr.c_str(), "nigh")) { + if (cmHasLiteralPrefix(rstr, "nigh")) { return cmCTest::NIGHTLY; } return cmCTest::EXPERIMENTAL; @@ -958,7 +954,7 @@ int cmCTest::GetTestModelFromString(const char* str) //###################################################################### int cmCTest::RunMakeCommand(const char* command, std::string& output, - int* retVal, const char* dir, int timeout, + int* retVal, const char* dir, cmDuration timeout, std::ostream& ofs, Encoding encoding) { // First generate the command and arguments @@ -990,7 +986,7 @@ int cmCTest::RunMakeCommand(const char* command, std::string& output, cmsysProcess_SetCommand(cp, &*argv.begin()); cmsysProcess_SetWorkingDirectory(cp, dir); cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1); - cmsysProcess_SetTimeout(cp, timeout); + cmsysProcess_SetTimeout(cp, timeout.count()); cmsysProcess_Execute(cp); // Initialize tick's @@ -1074,26 +1070,33 @@ int cmCTest::RunMakeCommand(const char* command, std::string& output, //###################################################################### int cmCTest::RunTest(std::vector<const char*> argv, std::string* output, - int* retVal, std::ostream* log, double testTimeOut, + int* retVal, std::ostream* log, cmDuration testTimeOut, std::vector<std::string>* environment, Encoding encoding) { bool modifyEnv = (environment && !environment->empty()); // determine how much time we have - double timeout = this->GetRemainingTimeAllowed() - 120; - if (this->TimeOut > 0 && this->TimeOut < timeout) { + cmDuration timeout = this->GetRemainingTimeAllowed(); + if (timeout != cmCTest::MaxDuration()) { + timeout -= std::chrono::minutes(2); + } + if (this->TimeOut > cmDuration::zero() && this->TimeOut < timeout) { timeout = this->TimeOut; } - if (testTimeOut > 0 && testTimeOut < this->GetRemainingTimeAllowed()) { + if (testTimeOut > cmDuration::zero() && + testTimeOut < this->GetRemainingTimeAllowed()) { timeout = testTimeOut; } // always have at least 1 second if we got to here - if (timeout <= 0) { - timeout = 1; - } - cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, - "Test timeout computed to be: " << timeout << "\n"); + if (timeout <= cmDuration::zero()) { + timeout = std::chrono::seconds(1); + } + cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "Test timeout computed to be: " + << (timeout == cmCTest::MaxDuration() + ? std::string("infinite") + : std::to_string(cmDurationTo<unsigned int>(timeout))) + << "\n"); if (cmSystemTools::SameFile(argv[0], cmSystemTools::GetCTestCommand()) && !this->ForceNewCTestProcess) { cmCTest inst; @@ -1110,10 +1113,12 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output, // make sure we pass the timeout in for any build and test // invocations. Since --build-generator is required this is a // good place to check for it, and to add the arguments in - if (strcmp(i, "--build-generator") == 0 && timeout > 0) { + if (strcmp(i, "--build-generator") == 0 && + timeout != cmCTest::MaxDuration() && + timeout > cmDuration::zero()) { args.push_back("--test-timeout"); std::ostringstream msg; - msg << timeout; + msg << cmDurationTo<unsigned int>(timeout); args.push_back(msg.str()); } args.push_back(i); @@ -1163,7 +1168,7 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output, cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1); } - cmsysProcess_SetTimeout(cp, timeout); + cmsysProcess_SetTimeout(cp, timeout.count()); cmsysProcess_Execute(cp); char* data; @@ -1421,7 +1426,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()); @@ -1518,7 +1523,7 @@ std::string cmCTest::Base64EncodeFile(std::string const& file) bool cmCTest::SubmitExtraFiles(const VectorOfStrings& files) { for (cmsys::String const& file : files) { - if (!cmSystemTools::FileExists(file.c_str())) { + if (!cmSystemTools::FileExists(file)) { cmCTestLog(this, ERROR_MESSAGE, "Cannot find extra file: " << file << " to submit." << std::endl;); return false; @@ -1760,7 +1765,7 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, if (this->CheckArgument(arg, "--timeout") && i < args.size() - 1) { i++; - double timeout = atof(args[i].c_str()); + auto timeout = cmDuration(atof(args[i].c_str())); this->GlobalTimeout = timeout; } @@ -1798,9 +1803,6 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, if (this->CheckArgument(arg, "-V", "--verbose")) { this->Verbose = true; } - if (this->CheckArgument(arg, "-B")) { - this->BatchJobs = true; - } if (this->CheckArgument(arg, "-VV", "--extra-verbose")) { this->ExtraVerbose = true; this->Verbose = true; @@ -2257,10 +2259,41 @@ void cmCTest::SetNotesFiles(const char* notes) this->NotesFiles = notes; } -void cmCTest::SetStopTime(std::string const& time) +void cmCTest::SetStopTime(std::string const& time_str) { - this->StopTime = time; - this->DetermineNextDayStop(); + + struct tm* lctime; + time_t current_time = time(nullptr); + lctime = gmtime(¤t_time); + int gm_hour = lctime->tm_hour; + time_t gm_time = mktime(lctime); + lctime = localtime(¤t_time); + int local_hour = lctime->tm_hour; + + int tzone_offset = local_hour - gm_hour; + if (gm_time > current_time && gm_hour < local_hour) { + // this means gm_time is on the next day + tzone_offset -= 24; + } else if (gm_time < current_time && gm_hour > local_hour) { + // this means gm_time is on the previous day + tzone_offset += 24; + } + + tzone_offset *= 100; + char buf[1024]; + sprintf(buf, "%d%02d%02d %s %+05i", lctime->tm_year + 1900, + lctime->tm_mon + 1, lctime->tm_mday, time_str.c_str(), tzone_offset); + + time_t stop_time = curl_getdate(buf, ¤t_time); + if (stop_time == -1) { + this->StopTime = std::chrono::system_clock::time_point(); + return; + } + this->StopTime = std::chrono::system_clock::from_time_t(stop_time); + + if (stop_time < current_time) { + this->StopTime += std::chrono::hours(24); + } } int cmCTest::ReadCustomConfigurationFileTree(const char* dir, cmMakefile* mf) @@ -2274,7 +2307,7 @@ int cmCTest::ReadCustomConfigurationFileTree(const char* dir, cmMakefile* mf) std::string fname = dir; fname += "/CTestCustom.cmake"; cmCTestLog(this, DEBUG, "* Check for file: " << fname << std::endl); - if (cmSystemTools::FileExists(fname.c_str())) { + if (cmSystemTools::FileExists(fname)) { cmCTestLog(this, DEBUG, "* Read custom CTest configuration file: " << fname << std::endl); bool erroroc = cmSystemTools::GetErrorOccuredFlag(); @@ -2294,7 +2327,7 @@ int cmCTest::ReadCustomConfigurationFileTree(const char* dir, cmMakefile* mf) std::string rexpr = dir; rexpr += "/CTestCustom.ctest"; cmCTestLog(this, DEBUG, "* Check for file: " << rexpr << std::endl); - if (!found && cmSystemTools::FileExists(rexpr.c_str())) { + if (!found && cmSystemTools::FileExists(rexpr)) { cmsys::Glob gl; gl.RecurseOn(); gl.FindFiles(rexpr); @@ -2361,10 +2394,8 @@ std::string cmCTest::GetShortPathToFile(const char* cfname) std::string fname = cmSystemTools::CollapseFullPath(cfname); // Find relative paths to both directories - std::string srcRelpath = - cmSystemTools::RelativePath(sourceDir.c_str(), fname.c_str()); - std::string bldRelpath = - cmSystemTools::RelativePath(buildDir.c_str(), fname.c_str()); + std::string srcRelpath = cmSystemTools::RelativePath(sourceDir, fname); + std::string bldRelpath = cmSystemTools::RelativePath(buildDir, fname); // If any contains "." it is not parent directory bool inSrc = srcRelpath.find("..") == std::string::npos; @@ -2418,38 +2449,6 @@ void cmCTest::EmptyCTestConfiguration() this->CTestConfiguration.clear(); } -void cmCTest::DetermineNextDayStop() -{ - struct tm* lctime; - time_t current_time = time(nullptr); - lctime = gmtime(¤t_time); - int gm_hour = lctime->tm_hour; - time_t gm_time = mktime(lctime); - lctime = localtime(¤t_time); - int local_hour = lctime->tm_hour; - - int tzone_offset = local_hour - gm_hour; - if (gm_time > current_time && gm_hour < local_hour) { - // this means gm_time is on the next day - tzone_offset -= 24; - } else if (gm_time < current_time && gm_hour > local_hour) { - // this means gm_time is on the previous day - tzone_offset += 24; - } - - tzone_offset *= 100; - char buf[1024]; - sprintf(buf, "%d%02d%02d %s %+05i", lctime->tm_year + 1900, - lctime->tm_mon + 1, lctime->tm_mday, this->StopTime.c_str(), - tzone_offset); - - time_t stop_time = curl_getdate(buf, ¤t_time); - - if (stop_time < current_time) { - this->NextDayStopTime = true; - } -} - void cmCTest::SetCTestConfiguration(const char* name, const char* value, bool suppress) { @@ -2567,7 +2566,8 @@ bool cmCTest::SetCTestConfigurationFromCMakeVariable( bool cmCTest::RunCommand(std::vector<std::string> const& args, std::string* stdOut, std::string* stdErr, int* retVal, - const char* dir, double timeout, Encoding encoding) + const char* dir, cmDuration timeout, + Encoding encoding) { std::vector<const char*> argv; argv.reserve(args.size() + 1); @@ -2585,7 +2585,7 @@ bool cmCTest::RunCommand(std::vector<std::string> const& args, if (cmSystemTools::GetRunCommandHideConsole()) { cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1); } - cmsysProcess_SetTimeout(cp, timeout); + cmsysProcess_SetTimeout(cp, timeout.count()); cmsysProcess_Execute(cp); std::vector<char> tempOutput; @@ -2778,10 +2778,10 @@ void cmCTest::Log(int logType, const char* file, int line, const char* msg, } } -double cmCTest::GetRemainingTimeAllowed() +cmDuration cmCTest::GetRemainingTimeAllowed() { if (!this->GetHandler("script")) { - return 1.0e7; + return cmCTest::MaxDuration(); } cmCTestScriptHandler* ch = @@ -2790,6 +2790,19 @@ double cmCTest::GetRemainingTimeAllowed() return ch->GetRemainingTimeAllowed(); } +cmDuration cmCTest::MaxDuration() +{ + return cmDuration(1.0e7); +} + +void cmCTest::SetRunCurrentScript(bool value) +{ + cmCTestScriptHandler* ch = + static_cast<cmCTestScriptHandler*>(this->GetHandler("script")); + + ch->SetRunCurrentScript(value); +} + void cmCTest::OutputTestErrors(std::vector<char> const& process_output) { std::string test_outputs("\n*** Test Failed:\n"); diff --git a/Source/cmCTest.h b/Source/cmCTest.h index dbd67dc..673a40e 100644 --- a/Source/cmCTest.h +++ b/Source/cmCTest.h @@ -5,8 +5,10 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include "cmDuration.h" #include "cmProcessOutput.h" #include "cmsys/String.hxx" +#include <chrono> #include <map> #include <set> #include <sstream> @@ -139,10 +141,10 @@ public: /** what is the configuraiton type, e.g. Debug, Release etc. */ std::string const& GetConfigType(); - double GetTimeOut() { return this->TimeOut; } - void SetTimeOut(double t) { this->TimeOut = t; } + cmDuration GetTimeOut() { return this->TimeOut; } + void SetTimeOut(cmDuration t) { this->TimeOut = t; } - double GetGlobalTimeout() { return this->GlobalTimeout; } + cmDuration GetGlobalTimeout() { return this->GlobalTimeout; } /** how many test to run at the same time */ int GetParallelLevel() { return this->ParallelLevel; } @@ -200,9 +202,11 @@ public: /** * Return the time remaining that the script is allowed to run in * seconds if the user has set the variable CTEST_TIME_LIMIT. If that has - * not been set it returns 1e7 seconds + * not been set it returns a very large duration. */ - double GetRemainingTimeAllowed(); + cmDuration GetRemainingTimeAllowed(); + + static cmDuration MaxDuration(); /** * Open file in the output directory and set the stream @@ -220,7 +224,10 @@ public: bool ShouldCompressTestOutput(); bool CompressString(std::string& str); - std::string GetStopTime() { return this->StopTime; } + std::chrono::system_clock::time_point GetStopTime() + { + return this->StopTime; + } void SetStopTime(std::string const& time); /** Used for parallel ctest job scheduling */ @@ -248,7 +255,8 @@ public: */ bool RunCommand(std::vector<std::string> const& args, std::string* stdOut, std::string* stdErr, int* retVal = nullptr, - const char* dir = nullptr, double timeout = 0.0, + const char* dir = nullptr, + cmDuration timeout = cmDuration::zero(), Encoding encoding = cmProcessOutput::Auto); /** @@ -268,7 +276,7 @@ public: * and retVal is return value or exception. */ int RunMakeCommand(const char* command, std::string& output, int* retVal, - const char* dir, int timeout, std::ostream& ofs, + const char* dir, cmDuration timeout, std::ostream& ofs, Encoding encoding = cmProcessOutput::Auto); /** Return the current tag */ @@ -315,7 +323,7 @@ public: * environment variables are restored to their previous values. */ int RunTest(std::vector<const char*> args, std::string* output, int* retVal, - std::ostream* logfile, double testTimeOut, + std::ostream* logfile, cmDuration testTimeOut, std::vector<std::string>* environment, Encoding encoding = cmProcessOutput::Auto); @@ -420,9 +428,6 @@ public: void SetFailover(bool failover) { this->Failover = failover; } bool GetFailover() { return this->Failover; } - void SetBatchJobs(bool batch = true) { this->BatchJobs = batch; } - bool GetBatchJobs() { return this->BatchJobs; } - bool GetVerbose() { return this->Verbose; } bool GetExtraVerbose() { return this->ExtraVerbose; } @@ -453,13 +458,14 @@ public: void GenerateSubprojectsOutput(cmXMLWriter& xml); std::vector<std::string> GetLabelsForSubprojects(); + void SetRunCurrentScript(bool value); + private: int RepeatTests; bool RepeatUntilFail; std::string ConfigType; std::string ScheduleType; - std::string StopTime; - bool NextDayStopTime; + std::chrono::system_clock::time_point StopTime; bool Verbose; bool ExtraVerbose; bool ProduceXML; @@ -468,7 +474,6 @@ private: bool UseHTTP10; bool PrintLabels; bool Failover; - bool BatchJobs; bool ForceNewCTestProcess; @@ -476,8 +481,6 @@ private: int GenerateNotesFile(const char* files); - void DetermineNextDayStop(); - // these are helper classes typedef std::map<std::string, cmCTestGenericHandler*> t_TestingHandlers; t_TestingHandlers TestingHandlers; @@ -487,7 +490,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 @@ -504,11 +506,9 @@ private: int TestModel; std::string SpecificTrack; - double TimeOut; - - double GlobalTimeout; + cmDuration TimeOut; - int LastStopTimeout; + cmDuration GlobalTimeout; int MaxTestNameWidth; diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx index 44095ec..fab2445 100644 --- a/Source/cmCacheManager.cxx +++ b/Source/cmCacheManager.cxx @@ -10,6 +10,7 @@ #include <string.h> #include "cmGeneratedFileStream.h" +#include "cmMessenger.h" #include "cmState.h" #include "cmSystemTools.h" #include "cmVersion.h" @@ -42,7 +43,7 @@ bool cmCacheManager::LoadCache(const std::string& path, bool internal, if (internal) { this->Cache.clear(); } - if (!cmSystemTools::FileExists(cacheFile.c_str())) { + if (!cmSystemTools::FileExists(cacheFile)) { this->CleanCMakeFiles(path); return false; } @@ -205,7 +206,8 @@ bool cmCacheManager::ReadPropertyEntry(std::string const& entryKey, return false; } -void cmCacheManager::WritePropertyEntries(std::ostream& os, CacheIterator i) +void cmCacheManager::WritePropertyEntries(std::ostream& os, CacheIterator i, + cmMessenger* messenger) { for (const char** p = this->PersistentProperties; *p; ++p) { if (const char* value = i.GetProperty(*p)) { @@ -221,11 +223,13 @@ void cmCacheManager::WritePropertyEntries(std::ostream& os, CacheIterator i) os << ":INTERNAL="; this->OutputValue(os, value); os << "\n"; + cmCacheManager::OutputNewlineTruncationWarning(os, key, value, + messenger); } } } -bool cmCacheManager::SaveCache(const std::string& path) +bool cmCacheManager::SaveCache(const std::string& path, cmMessenger* messenger) { std::string cacheFile = path; cacheFile += "/CMakeCache.txt"; @@ -316,7 +320,10 @@ bool cmCacheManager::SaveCache(const std::string& path) this->OutputKey(fout, i.first); fout << ":" << cmState::CacheEntryTypeToString(t) << "="; this->OutputValue(fout, ce.Value); - fout << "\n\n"; + fout << "\n"; + cmCacheManager::OutputNewlineTruncationWarning(fout, i.first, ce.Value, + messenger); + fout << "\n"; } } @@ -333,7 +340,7 @@ bool cmCacheManager::SaveCache(const std::string& path) } cmStateEnums::CacheEntryType t = i.GetType(); - this->WritePropertyEntries(fout, i); + this->WritePropertyEntries(fout, i, messenger); if (t == cmStateEnums::INTERNAL) { // Format is key:type=value if (const char* help = i.GetProperty("HELPSTRING")) { @@ -343,13 +350,15 @@ bool cmCacheManager::SaveCache(const std::string& path) fout << ":" << cmState::CacheEntryTypeToString(t) << "="; this->OutputValue(fout, i.GetValue()); fout << "\n"; + cmCacheManager::OutputNewlineTruncationWarning(fout, i.GetName(), + i.GetValue(), messenger); } } fout << "\n"; fout.Close(); std::string checkCacheFile = path; checkCacheFile += cmake::GetCMakeFilesDirectory(); - cmSystemTools::MakeDirectory(checkCacheFile.c_str()); + cmSystemTools::MakeDirectory(checkCacheFile); checkCacheFile += "/cmake.check_cache"; cmsys::ofstream checkCache(checkCacheFile.c_str()); if (!checkCache) { @@ -368,7 +377,7 @@ bool cmCacheManager::DeleteCache(const std::string& path) cmSystemTools::ConvertToUnixSlashes(cacheFile); std::string cmakeFiles = cacheFile; cacheFile += "/CMakeCache.txt"; - if (cmSystemTools::FileExists(cacheFile.c_str())) { + if (cmSystemTools::FileExists(cacheFile)) { cmSystemTools::RemoveFile(cacheFile); // now remove the files in the CMakeFiles directory // this cleans up language cache files @@ -390,6 +399,19 @@ void cmCacheManager::OutputKey(std::ostream& fout, std::string const& key) void cmCacheManager::OutputValue(std::ostream& fout, std::string const& value) { + // look for and truncate newlines + std::string::size_type newline = value.find('\n'); + if (newline != std::string::npos) { + std::string truncated = value.substr(0, newline); + OutputValueNoNewlines(fout, truncated); + } else { + OutputValueNoNewlines(fout, value); + } +} + +void cmCacheManager::OutputValueNoNewlines(std::ostream& fout, + std::string const& value) +{ // if value has trailing space or tab, enclose it in single quotes if (!value.empty() && (value[value.size() - 1] == ' ' || value[value.size() - 1] == '\t')) { @@ -423,6 +445,50 @@ void cmCacheManager::OutputHelpString(std::ostream& fout, } } +void cmCacheManager::OutputWarningComment(std::ostream& fout, + std::string const& message, + bool wrapSpaces) +{ + std::string::size_type end = message.size(); + std::string oneLine; + std::string::size_type pos = 0; + for (std::string::size_type i = 0; i <= end; i++) { + if ((i == end) || (message[i] == '\n') || + ((i - pos >= 60) && (message[i] == ' ') && wrapSpaces)) { + fout << "# "; + if (message[pos] == '\n') { + pos++; + fout << "\\n"; + } + oneLine = message.substr(pos, i - pos); + fout << oneLine << "\n"; + pos = i; + } + } +} + +void cmCacheManager::OutputNewlineTruncationWarning(std::ostream& fout, + std::string const& key, + std::string const& value, + cmMessenger* messenger) +{ + if (value.find('\n') != std::string::npos) { + if (messenger) { + std::string message = "Value of "; + message += key; + message += " contained a newline; truncating"; + messenger->IssueMessage(cmake::WARNING, message); + } + + std::string comment = "WARNING: Value of "; + comment += key; + comment += " contained a newline and was truncated. Original value:"; + + OutputWarningComment(fout, comment, true); + OutputWarningComment(fout, value, false); + } +} + void cmCacheManager::RemoveCacheEntry(const std::string& key) { CacheEntryMap::iterator i = this->Cache.find(key); diff --git a/Source/cmCacheManager.h b/Source/cmCacheManager.h index e9e6570..73923d1 100644 --- a/Source/cmCacheManager.h +++ b/Source/cmCacheManager.h @@ -15,7 +15,7 @@ #include "cmPropertyMap.h" #include "cmStateTypes.h" -class cmake; +class cmMessenger; /** \class cmCacheManager * \brief Control class for cmake's cache @@ -107,8 +107,8 @@ public: std::set<std::string>& excludes, std::set<std::string>& includes); - ///! Save cache for given makefile. Saves to ouput path/CMakeCache.txt - bool SaveCache(const std::string& path); + ///! Save cache for given makefile. Saves to output path/CMakeCache.txt + bool SaveCache(const std::string& path, cmMessenger* messenger); ///! Delete the cache given bool DeleteCache(const std::string& path); @@ -218,16 +218,25 @@ protected: unsigned int CacheMinorVersion; private: - cmake* CMakeInstance; typedef std::map<std::string, CacheEntry> CacheEntryMap; static void OutputHelpString(std::ostream& fout, const std::string& helpString); + static void OutputWarningComment(std::ostream& fout, + std::string const& message, + bool wrapSpaces); + static void OutputNewlineTruncationWarning(std::ostream& fout, + std::string const& key, + std::string const& value, + cmMessenger* messenger); static void OutputKey(std::ostream& fout, std::string const& key); static void OutputValue(std::ostream& fout, std::string const& value); + static void OutputValueNoNewlines(std::ostream& fout, + std::string const& value); static const char* PersistentProperties[]; bool ReadPropertyEntry(std::string const& key, CacheEntry& e); - void WritePropertyEntries(std::ostream& os, CacheIterator i); + void WritePropertyEntries(std::ostream& os, CacheIterator i, + cmMessenger* messenger); CacheEntryMap Cache; // Only cmake and cmState should be able to add cache values 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/cmCommands.cxx b/Source/cmCommands.cxx index 8a7d9bd..a1de8b1 100644 --- a/Source/cmCommands.cxx +++ b/Source/cmCommands.cxx @@ -343,7 +343,7 @@ void GetProjectCommandsInScriptMode(cmState* state) CM_UNEXPECTED_PROJECT_COMMAND("try_compile"); CM_UNEXPECTED_PROJECT_COMMAND("try_run"); - // deprected commands + // deprecated commands CM_UNEXPECTED_PROJECT_COMMAND("export_library_dependencies"); CM_UNEXPECTED_PROJECT_COMMAND("load_command"); CM_UNEXPECTED_PROJECT_COMMAND("output_required_files"); diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index 1189606..d6d8eb0 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -159,7 +159,7 @@ std::vector<std::string> cmCommonTargetGenerator::GetLinkedTargetDirectories() std::string di = lg->GetCurrentBinaryDirectory(); di += "/"; di += lg->GetTargetDirectory(linkee); - dirs.push_back(di); + dirs.push_back(std::move(di)); } } } diff --git a/Source/cmComputeComponentGraph.cxx b/Source/cmComputeComponentGraph.cxx index 9ec98ae..a7dc1ca 100644 --- a/Source/cmComputeComponentGraph.cxx +++ b/Source/cmComputeComponentGraph.cxx @@ -88,7 +88,7 @@ void cmComputeComponentGraph::TarjanVisit(int i) if (this->TarjanEntries[i].Root == i) { // Yes. Create it. int c = static_cast<int>(this->Components.size()); - this->Components.push_back(NodeList()); + this->Components.emplace_back(); NodeList& component = this->Components[c]; // Populate the component list. @@ -125,8 +125,8 @@ void cmComputeComponentGraph::TransferEdges() if (i_component != j_component) { // We do not attempt to combine duplicate edges, but instead // store the inter-component edges with suitable multiplicity. - this->ComponentGraph[i_component].push_back( - cmGraphEdge(j_component, ni.IsStrong())); + this->ComponentGraph[i_component].emplace_back(j_component, + ni.IsStrong()); } } } diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index d9efc2e..354de36 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -285,9 +285,9 @@ std::map<std::string, int>::iterator cmComputeLinkDepends::AllocateLinkEntry( item, static_cast<int>(this->EntryList.size())); std::map<std::string, int>::iterator lei = this->LinkEntryIndex.insert(index_entry).first; - this->EntryList.push_back(LinkEntry()); + this->EntryList.emplace_back(); this->InferredDependSets.push_back(nullptr); - this->EntryConstraintGraph.push_back(EdgeList()); + this->EntryConstraintGraph.emplace_back(); return lei; } @@ -472,8 +472,7 @@ void cmComputeLinkDepends::AddVarLinkEntries(int depender_index, // If the library is meant for this link type then use it. if (llt == GENERAL_LibraryType || llt == this->LinkType) { - cmLinkItem item(d, this->FindTargetToLink(depender_index, d)); - actual_libs.push_back(item); + actual_libs.emplace_back(d, this->FindTargetToLink(depender_index, d)); } else if (this->OldLinkDirMode) { cmLinkItem item(d, this->FindTargetToLink(depender_index, d)); this->CheckWrongConfigItem(item); diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index fb13a58..8a5a6de 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -498,8 +498,8 @@ bool cmComputeLinkInformation::Compute() cmStateEnums::ArtifactType artifact = implib ? cmStateEnums::ImportLibraryArtifact : cmStateEnums::RuntimeBinaryArtifact; - std::string lib = tgt->GetFullPath(this->Config, artifact, true); - this->OldLinkDirItems.push_back(lib); + this->OldLinkDirItems.push_back( + tgt->GetFullPath(this->Config, artifact, true)); } } @@ -598,13 +598,13 @@ void cmComputeLinkInformation::AddItem(std::string const& item, std::string exe = tgt->GetFullPath(config, artifact, true); linkItem += exe; - this->Items.push_back(Item(linkItem, true, tgt)); - this->Depends.push_back(exe); + this->Items.emplace_back(linkItem, true, tgt); + this->Depends.push_back(std::move(exe)); } else if (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) { // Add the interface library as an item so it can be considered as part // of COMPATIBLE_INTERFACE_ enforcement. The generators will ignore // this for the actual link line. - this->Items.push_back(Item(std::string(), false, tgt)); + this->Items.emplace_back(std::string(), false, tgt); // Also add the item the interface specifies to be used in its place. std::string const& libName = tgt->GetImportedLibName(config); @@ -632,7 +632,7 @@ void cmComputeLinkInformation::AddItem(std::string const& item, } } else { // This is not a CMake target. Use the name given. - if (cmSystemTools::FileIsFullPath(item.c_str())) { + if (cmSystemTools::FileIsFullPath(item)) { if (cmSystemTools::FileIsDirectory(item)) { // This is a directory. this->AddDirectoryItem(item); @@ -668,13 +668,13 @@ void cmComputeLinkInformation::AddSharedDepItem(std::string const& item, } else { // Skip items that are not full paths. We will not be able to // reliably specify them. - if (!cmSystemTools::FileIsFullPath(item.c_str())) { + if (!cmSystemTools::FileIsFullPath(item)) { return; } // Get the name of the library from the file name. std::string file = cmSystemTools::GetFilenameName(item); - if (!this->ExtractSharedLibraryName.find(file.c_str())) { + if (!this->ExtractSharedLibraryName.find(file)) { // This is not the name of a shared library. return; } @@ -913,11 +913,9 @@ std::string cmComputeLinkInformation::CreateExtensionRegex( // Finish the list. libext += ")"; - // Add an optional OpenBSD version component. - if (this->OpenBSD) { - libext += "(\\.[0-9]+\\.[0-9]+)?"; - } else if (type == LinkShared) { - libext += "(\\.[0-9]+)?"; + // Add an optional OpenBSD-style version or major.minor.version component. + if (this->OpenBSD || type == LinkShared) { + libext += "(\\.[0-9]+)*"; } libext += "$"; @@ -952,10 +950,10 @@ void cmComputeLinkInformation::SetCurrentLinkType(LinkType lt) if (this->LinkTypeEnabled) { switch (this->CurrentLinkType) { case LinkStatic: - this->Items.push_back(Item(this->StaticLinkTypeFlag, false)); + this->Items.emplace_back(this->StaticLinkTypeFlag, false); break; case LinkShared: - this->Items.push_back(Item(this->SharedLinkTypeFlag, false)); + this->Items.emplace_back(this->SharedLinkTypeFlag, false); break; default: break; @@ -991,7 +989,7 @@ void cmComputeLinkInformation::AddTargetItem(std::string const& item, // If this platform wants a flag before the full path, add it. if (!this->LibLinkFileFlag.empty()) { - this->Items.push_back(Item(this->LibLinkFileFlag, false)); + this->Items.emplace_back(this->LibLinkFileFlag, false); } // For compatibility with CMake 2.4 include the item's directory in @@ -1003,7 +1001,7 @@ void cmComputeLinkInformation::AddTargetItem(std::string const& item, } // Now add the full path to the library. - this->Items.push_back(Item(item, true, target)); + this->Items.emplace_back(item, true, target); } void cmComputeLinkInformation::AddFullItem(std::string const& item) @@ -1058,11 +1056,11 @@ void cmComputeLinkInformation::AddFullItem(std::string const& item) // If this platform wants a flag before the full path, add it. if (!this->LibLinkFileFlag.empty()) { - this->Items.push_back(Item(this->LibLinkFileFlag, false)); + this->Items.emplace_back(this->LibLinkFileFlag, false); } // Now add the full path to the library. - this->Items.push_back(Item(item, true)); + this->Items.emplace_back(item, true); } bool cmComputeLinkInformation::CheckImplicitDirItem(std::string const& item) @@ -1149,7 +1147,7 @@ void cmComputeLinkInformation::AddUserItem(std::string const& item, this->SetCurrentLinkType(this->StartLinkType); // Use the item verbatim. - this->Items.push_back(Item(item, false)); + this->Items.emplace_back(item, false); return; } @@ -1221,7 +1219,7 @@ void cmComputeLinkInformation::AddUserItem(std::string const& item, std::string out = this->LibLinkFlag; out += lib; out += this->LibLinkSuffix; - this->Items.push_back(Item(out, false)); + this->Items.emplace_back(out, false); // Here we could try to find the library the linker will find and // add a runtime information entry for it. It would probably not be @@ -1256,10 +1254,10 @@ void cmComputeLinkInformation::AddFrameworkItem(std::string const& item) this->AddLibraryRuntimeInfo(full_fw); // Add the item using the -framework option. - this->Items.push_back(Item("-framework", false)); + this->Items.emplace_back("-framework", false); cmOutputConverter converter(this->Makefile->GetStateSnapshot()); fw = converter.EscapeForShell(fw); - this->Items.push_back(Item(fw, false)); + this->Items.emplace_back(fw, false); } void cmComputeLinkInformation::AddDirectoryItem(std::string const& item) @@ -1744,12 +1742,13 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, cmSystemTools::ConvertToUnixSlashes(d); } if (emitted.insert(d).second) { - runtimeDirs.push_back(d); + runtimeDirs.push_back(std::move(d)); } } else if (use_link_rpath) { // Do not add any path inside the source or build tree. - const char* topSourceDir = this->CMakeInstance->GetHomeDirectory(); - const char* topBinaryDir = + std::string const& topSourceDir = + this->CMakeInstance->GetHomeDirectory(); + std::string const& topBinaryDir = this->CMakeInstance->GetHomeOutputDirectory(); if (!cmSystemTools::ComparePath(ri, topSourceDir) && !cmSystemTools::ComparePath(ri, topBinaryDir) && @@ -1766,7 +1765,7 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, cmSystemTools::ConvertToUnixSlashes(d); } if (emitted.insert(d).second) { - runtimeDirs.push_back(d); + runtimeDirs.push_back(std::move(d)); } } } diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx index 963c2df..18767a3 100644 --- a/Source/cmComputeTargetDepends.cxx +++ b/Source/cmComputeTargetDepends.cxx @@ -200,7 +200,7 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index) std::vector<std::string> configs; depender->Makefile->GetConfigurations(configs); if (configs.empty()) { - configs.push_back(""); + configs.emplace_back(); } for (std::string const& it : configs) { std::vector<cmSourceFile const*> objectFiles; @@ -369,8 +369,7 @@ void cmComputeTargetDepends::AddTargetDepend(int depender_index, int dependee_index = tii->second; // Add this entry to the dependency graph. - this->InitialGraph[depender_index].push_back( - cmGraphEdge(dependee_index, !linking)); + this->InitialGraph[depender_index].emplace_back(dependee_index, !linking); } } @@ -504,7 +503,7 @@ bool cmComputeTargetDepends::IntraComponent(std::vector<int> const& cmap, for (cmGraphEdge const& edge : el) { int j = edge; if (cmap[j] == c && edge.IsStrong()) { - this->FinalGraph[i].push_back(cmGraphEdge(j, true)); + this->FinalGraph[i].emplace_back(j, true); if (!this->IntraComponent(cmap, c, j, head, emitted, visited)) { return false; } @@ -513,7 +512,7 @@ bool cmComputeTargetDepends::IntraComponent(std::vector<int> const& cmap, // Prepend to a linear linked-list of intra-component edges. if (*head >= 0) { - this->FinalGraph[i].push_back(cmGraphEdge(*head, false)); + this->FinalGraph[i].emplace_back(*head, false); } else { this->ComponentTail[c] = i; } @@ -563,8 +562,8 @@ bool cmComputeTargetDepends::ComputeFinalDepends( for (cmGraphEdge const& ni : nl) { int dependee_component = ni; int dependee_component_head = this->ComponentHead[dependee_component]; - this->FinalGraph[depender_component_tail].push_back( - cmGraphEdge(dependee_component_head, ni.IsStrong())); + this->FinalGraph[depender_component_tail].emplace_back( + dependee_component_head, ni.IsStrong()); } } return true; diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx index 90b3f6d..172ef92 100644 --- a/Source/cmConditionEvaluator.cxx +++ b/Source/cmConditionEvaluator.cxx @@ -494,7 +494,7 @@ bool cmConditionEvaluator::HandleLevel1(cmArgumentList& newArgs, std::string&, if (argP1len > 4 && argP1->GetValue().substr(0, 4) == "ENV{" && argP1->GetValue().operator[](argP1len - 1) == '}') { std::string env = argP1->GetValue().substr(4, argP1len - 5); - bdef = cmSystemTools::HasEnv(env.c_str()); + bdef = cmSystemTools::HasEnv(env); } else { bdef = this->Makefile.IsDefinitionSet(argP1->GetValue()); } 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/cmConfigureFileCommand.cxx b/Source/cmConfigureFileCommand.cxx index 18005f2..b5a639a 100644 --- a/Source/cmConfigureFileCommand.cxx +++ b/Source/cmConfigureFileCommand.cxx @@ -51,7 +51,7 @@ bool cmConfigureFileCommand::InitialPass(std::vector<std::string> const& args, this->OutputFile += cmSystemTools::GetFilenameName(inFile); } - if (!this->Makefile->CanIWriteThisFile(this->OutputFile.c_str())) { + if (!this->Makefile->CanIWriteThisFile(this->OutputFile)) { std::string e = "attempted to configure a file: " + this->OutputFile + " into a source directory."; this->SetError(e); 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/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index fd258fe..34c6175 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -391,7 +391,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, } } // make sure the binary directory exists - cmSystemTools::MakeDirectory(this->BinaryDirectory.c_str()); + cmSystemTools::MakeDirectory(this->BinaryDirectory); // do not allow recursive try Compiles if (this->BinaryDirectory == this->Makefile->GetHomeOutputDirectory()) { @@ -631,13 +631,13 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, kCMAKE_TRY_COMPILE_OSX_ARCHITECTURES)) { vars.erase(kCMAKE_OSX_ARCHITECTURES); std::string flag = "-DCMAKE_OSX_ARCHITECTURES=" + std::string(tcArchs); - cmakeFlags.push_back(flag); + cmakeFlags.push_back(std::move(flag)); } for (std::string const& var : vars) { if (const char* val = this->Makefile->GetDefinition(var)) { std::string flag = "-D" + var + "=" + val; - cmakeFlags.push_back(flag); + cmakeFlags.push_back(std::move(flag)); } } } @@ -864,18 +864,17 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, return res; } -void cmCoreTryCompile::CleanupFiles(const char* binDir) +void cmCoreTryCompile::CleanupFiles(std::string const& binDir) { - if (!binDir) { + if (binDir.empty()) { return; } - std::string bdir = binDir; - if (bdir.find("CMakeTmp") == std::string::npos) { + if (binDir.find("CMakeTmp") == std::string::npos) { cmSystemTools::Error( "TRY_COMPILE attempt to remove -rf directory that does not contain " "CMakeTmp:", - binDir); + binDir.c_str()); return; } @@ -889,7 +888,7 @@ void cmCoreTryCompile::CleanupFiles(const char* binDir) std::string const fullPath = std::string(binDir).append("/").append(fileName); if (cmSystemTools::FileIsDirectory(fullPath)) { - this->CleanupFiles(fullPath.c_str()); + this->CleanupFiles(fullPath); cmSystemTools::RemoveADirectory(fullPath); } else { #ifdef _WIN32 @@ -897,9 +896,8 @@ void cmCoreTryCompile::CleanupFiles(const char* binDir) // cannot delete them immediately. Try a few times. cmSystemTools::WindowsFileRetry retry = cmSystemTools::GetWindowsFileRetry(); - while (!cmSystemTools::RemoveFile(fullPath.c_str()) && - --retry.Count && - cmSystemTools::FileExists(fullPath.c_str())) { + while (!cmSystemTools::RemoveFile(fullPath) && --retry.Count && + cmSystemTools::FileExists(fullPath)) { cmSystemTools::Delay(retry.Delay); } if (retry.Count == 0) @@ -938,7 +936,7 @@ void cmCoreTryCompile::FindOutputFile(const std::string& targetName, // a list of directories where to search for the compilation result // at first directly in the binary dir std::vector<std::string> searchDirs; - searchDirs.push_back(""); + searchDirs.emplace_back(); const char* config = this->Makefile->GetDefinition("CMAKE_TRY_COMPILE_CONFIGURATION"); @@ -946,12 +944,12 @@ void cmCoreTryCompile::FindOutputFile(const std::string& targetName, if (config && config[0]) { std::string tmp = "/"; tmp += config; - searchDirs.push_back(tmp); + searchDirs.push_back(std::move(tmp)); } searchDirs.push_back("/Debug"); #if defined(__APPLE__) std::string app = "/Debug/" + targetName + ".app"; - searchDirs.push_back(app); + searchDirs.push_back(std::move(app)); #endif searchDirs.push_back("/Development"); @@ -959,7 +957,7 @@ void cmCoreTryCompile::FindOutputFile(const std::string& targetName, std::string command = this->BinaryDirectory; command += sdir; command += tmpOutputFile; - if (cmSystemTools::FileExists(command.c_str())) { + if (cmSystemTools::FileExists(command)) { this->OutputFile = cmSystemTools::CollapseFullPath(command); return; } diff --git a/Source/cmCoreTryCompile.h b/Source/cmCoreTryCompile.h index 365154d..6f35a54 100644 --- a/Source/cmCoreTryCompile.h +++ b/Source/cmCoreTryCompile.h @@ -33,7 +33,7 @@ protected: * This way we do not have to rely on the timing and * dependencies of makefiles. */ - void CleanupFiles(const char* binDir); + void CleanupFiles(std::string const& binDir); /** * This tries to find the (executable) file created by 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/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx index 3d816d5..136cf39 100644 --- a/Source/cmCustomCommandGenerator.cxx +++ b/Source/cmCustomCommandGenerator.cxx @@ -8,12 +8,12 @@ #include "cmGeneratorTarget.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" -#include "cmOutputConverter.h" #include "cmStateTypes.h" #include "cmSystemTools.h" #include <memory> // IWYU pragma: keep #include <stddef.h> +#include <utility> cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc, const std::string& config, @@ -37,10 +37,10 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc, cmSystemTools::ExpandListArgument(parsed_arg, ExpandedArg); argv.insert(argv.end(), ExpandedArg.begin(), ExpandedArg.end()); } else { - argv.push_back(parsed_arg); + argv.push_back(std::move(parsed_arg)); } } - this->CommandLines.push_back(argv); + this->CommandLines.push_back(std::move(argv)); } std::vector<std::string> depends = this->CC.GetDepends(); @@ -50,7 +50,7 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc, cmSystemTools::ExpandListArgument(cge->Evaluate(this->LG, this->Config), result); for (std::string& it : result) { - if (cmSystemTools::FileIsFullPath(it.c_str())) { + if (cmSystemTools::FileIsFullPath(it)) { it = cmSystemTools::CollapseFullPath(it); } } @@ -166,8 +166,7 @@ void cmCustomCommandGenerator::AppendArguments(unsigned int c, if (this->OldStyle) { cmd += escapeForShellOldStyle(arg); } else { - cmOutputConverter converter(this->LG->GetStateSnapshot()); - cmd += converter.EscapeForShell(arg, this->MakeVars); + cmd += this->LG->EscapeForShell(arg, this->MakeVars); } } } diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx index 1ab3fa2..62bc8d9 100644 --- a/Source/cmDependsC.cxx +++ b/Source/cmDependsC.cxx @@ -131,14 +131,12 @@ bool cmDependsC::WriteDependencies(const std::set<std::string>& sources, // If not a full path, find the file in the include path. std::string fullName; - if ((srcFiles > 0) || - cmSystemTools::FileIsFullPath(current.FileName.c_str())) { - if (cmSystemTools::FileExists(current.FileName.c_str(), true)) { + if ((srcFiles > 0) || cmSystemTools::FileIsFullPath(current.FileName)) { + if (cmSystemTools::FileExists(current.FileName, true)) { fullName = current.FileName; } } else if (!current.QuotedLocation.empty() && - cmSystemTools::FileExists(current.QuotedLocation.c_str(), - true)) { + cmSystemTools::FileExists(current.QuotedLocation, true)) { // The include statement producing this entry was a double-quote // include and the included file is present in the directory of // the source containing the include statement. @@ -157,7 +155,7 @@ bool cmDependsC::WriteDependencies(const std::set<std::string>& sources, cmSystemTools::CollapseCombinedPath(i, current.FileName); // Look for the file in this location. - if (cmSystemTools::FileExists(tempPathStr.c_str(), true)) { + if (cmSystemTools::FileExists(tempPathStr, true)) { fullName = tempPathStr; HeaderLocationCache[current.FileName] = fullName; break; @@ -226,15 +224,14 @@ bool cmDependsC::WriteDependencies(const std::set<std::string>& sources, // directory. We must do the same here. std::string binDir = this->LocalGenerator->GetBinaryDirectory(); std::string obj_i = this->LocalGenerator->ConvertToRelativePath(binDir, obj); - std::string obj_m = cmSystemTools::ConvertToOutputPath(obj_i.c_str()); + std::string obj_m = cmSystemTools::ConvertToOutputPath(obj_i); internalDepends << obj_i << std::endl; for (std::string const& dep : dependencies) { - makeDepends - << obj_m << ": " - << cmSystemTools::ConvertToOutputPath( - this->LocalGenerator->ConvertToRelativePath(binDir, dep).c_str()) - << std::endl; + makeDepends << obj_m << ": " + << cmSystemTools::ConvertToOutputPath( + this->LocalGenerator->ConvertToRelativePath(binDir, dep)) + << std::endl; internalDepends << " " << dep << std::endl; } makeDepends << std::endl; @@ -303,7 +300,7 @@ void cmDependsC::ReadCacheFile() if (line != "-") { entry.QuotedLocation = line; } - cacheEntry->UnscannedEntries.push_back(entry); + cacheEntry->UnscannedEntries.push_back(std::move(entry)); } } } @@ -363,7 +360,7 @@ void cmDependsC::Scan(std::istream& is, const char* directory, entry.FileName = this->IncludeRegexLine.match(2); cmSystemTools::ConvertToUnixSlashes(entry.FileName); if (this->IncludeRegexLine.match(3) == "\"" && - !cmSystemTools::FileIsFullPath(entry.FileName.c_str())) { + !cmSystemTools::FileIsFullPath(entry.FileName)) { // This was a double-quoted include with a relative path. We // must check for the file in the directory containing the // file we are scanning. diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx index fdbc086..1a66ca0 100644 --- a/Source/cmDependsFortran.cxx +++ b/Source/cmDependsFortran.cxx @@ -312,13 +312,13 @@ bool cmDependsFortran::WriteDependenciesReal(const char* obj, // Write the include dependencies to the output stream. std::string binDir = this->LocalGenerator->GetBinaryDirectory(); std::string obj_i = this->MaybeConvertToRelativePath(binDir, obj); - std::string obj_m = cmSystemTools::ConvertToOutputPath(obj_i.c_str()); + std::string obj_m = cmSystemTools::ConvertToOutputPath(obj_i); internalDepends << obj_i << std::endl; internalDepends << " " << src << std::endl; for (std::string const& i : info.Includes) { makeDepends << obj_m << ": " << cmSystemTools::ConvertToOutputPath( - this->MaybeConvertToRelativePath(binDir, i).c_str()) + this->MaybeConvertToRelativePath(binDir, i)) << std::endl; internalDepends << " " << i << std::endl; } @@ -331,24 +331,6 @@ bool cmDependsFortran::WriteDependenciesReal(const char* obj, continue; } - // If the module is provided in this target special handling is - // needed. - if (this->Internal->TargetProvides.find(i) != - this->Internal->TargetProvides.end()) { - // The module is provided by a different source in the same - // target. Add the proxy dependency to make sure the other - // source builds first. - std::string proxy = stamp_dir; - proxy += "/"; - proxy += i; - proxy += ".mod.proxy"; - proxy = cmSystemTools::ConvertToOutputPath( - this->MaybeConvertToRelativePath(binDir, proxy).c_str()); - - // since we require some things add them to our list of requirements - makeDepends << obj_m << ".requires: " << proxy << std::endl; - } - // The object file should depend on timestamped files for the // modules it uses. TargetRequiresMap::const_iterator required = @@ -359,7 +341,7 @@ bool cmDependsFortran::WriteDependenciesReal(const char* obj, if (!required->second.empty()) { // This module is known. Depend on its timestamp file. std::string stampFile = cmSystemTools::ConvertToOutputPath( - this->MaybeConvertToRelativePath(binDir, required->second).c_str()); + this->MaybeConvertToRelativePath(binDir, required->second)); makeDepends << obj_m << ": " << stampFile << "\n"; } else { // This module is not known to CMake. Try to locate it where @@ -367,28 +349,16 @@ bool cmDependsFortran::WriteDependenciesReal(const char* obj, std::string module; if (this->FindModule(i, module)) { module = cmSystemTools::ConvertToOutputPath( - this->MaybeConvertToRelativePath(binDir, module).c_str()); + this->MaybeConvertToRelativePath(binDir, module)); makeDepends << obj_m << ": " << module << "\n"; } } } - // Write provided modules to the output stream. - for (std::string const& i : info.Provides) { - std::string proxy = stamp_dir; - proxy += "/"; - proxy += i; - proxy += ".mod.proxy"; - proxy = cmSystemTools::ConvertToOutputPath( - this->MaybeConvertToRelativePath(binDir, proxy).c_str()); - makeDepends << proxy << ": " << obj_m << ".provides" << std::endl; - } - // If any modules are provided then they must be converted to stamp files. if (!info.Provides.empty()) { // Create a target to copy the module after the object file // changes. - makeDepends << obj_m << ".provides.build:\n"; for (std::string const& i : info.Provides) { // Include this module in the set provided by this target. this->Internal->TargetProvides.insert(i); @@ -407,11 +377,25 @@ bool cmDependsFortran::WriteDependenciesReal(const char* obj, stampFile += "/"; stampFile += m; stampFile += ".mod.stamp"; - stampFile = this->LocalGenerator->ConvertToOutputFormat( - this->MaybeConvertToRelativePath(binDir, stampFile), - cmOutputConverter::SHELL); + stampFile = this->MaybeConvertToRelativePath(binDir, stampFile); + std::string const stampFileForShell = + this->LocalGenerator->ConvertToOutputFormat(stampFile, + cmOutputConverter::SHELL); + std::string const stampFileForMake = + cmSystemTools::ConvertToOutputPath(stampFile); + + makeDepends << obj_m << ".provides.build" + << ": " << stampFileForMake << "\n"; + // Note that when cmake_copy_f90_mod finds that a module file + // and the corresponding stamp file have no differences, the stamp + // file is not updated. In such case the stamp file will be always + // older than its prerequisite and trigger cmake_copy_f90_mod + // on each new build. This is expected behavior for incremental + // builds and can not be changed without preforming recursive make + // calls that would considerably slow down the building process. + makeDepends << stampFileForMake << ": " << obj_m << "\n"; makeDepends << "\t$(CMAKE_COMMAND) -E cmake_copy_f90_mod " << modFile - << " " << stampFile; + << " " << stampFileForShell; cmMakefile* mf = this->LocalGenerator->GetMakefile(); const char* cid = mf->GetDefinition("CMAKE_Fortran_COMPILER_ID"); if (cid && *cid) { @@ -419,8 +403,8 @@ bool cmDependsFortran::WriteDependenciesReal(const char* obj, } makeDepends << "\n"; } - // After copying the modules update the timestamp file so that - // copying will not be done again until the source rebuilds. + makeDepends << obj_m << ".provides.build:\n"; + // After copying the modules update the timestamp file. makeDepends << "\t$(CMAKE_COMMAND) -E touch " << obj_m << ".provides.build\n"; @@ -429,7 +413,7 @@ bool cmDependsFortran::WriteDependenciesReal(const char* obj, std::string driver = this->TargetDirectory; driver += "/build"; driver = cmSystemTools::ConvertToOutputPath( - this->MaybeConvertToRelativePath(binDir, driver).c_str()); + this->MaybeConvertToRelativePath(binDir, driver)); makeDepends << driver << ": " << obj_m << ".provides.build\n"; } @@ -451,7 +435,7 @@ bool cmDependsFortran::FindModule(std::string const& name, std::string& module) fullName = ip; fullName += "/"; fullName += mod_lower; - if (cmSystemTools::FileExists(fullName.c_str(), true)) { + if (cmSystemTools::FileExists(fullName, true)) { module = fullName; return true; } @@ -460,7 +444,7 @@ bool cmDependsFortran::FindModule(std::string const& name, std::string& module) fullName = ip; fullName += "/"; fullName += mod_upper; - if (cmSystemTools::FileExists(fullName.c_str(), true)) { + if (cmSystemTools::FileExists(fullName, true)) { module = fullName; return true; } @@ -497,7 +481,7 @@ bool cmDependsFortran::CopyModule(const std::vector<std::string>& args) mod += ".mod"; mod_upper += ".mod"; mod_lower += ".mod"; - if (cmSystemTools::FileExists(mod_upper.c_str(), true)) { + if (cmSystemTools::FileExists(mod_upper, true)) { if (cmDependsFortran::ModulesDiffer(mod_upper.c_str(), stamp.c_str(), compilerId.c_str())) { if (!cmSystemTools::CopyFileAlways(mod_upper, stamp)) { @@ -508,7 +492,7 @@ bool cmDependsFortran::CopyModule(const std::vector<std::string>& args) } return true; } - if (cmSystemTools::FileExists(mod_lower.c_str(), true)) { + if (cmSystemTools::FileExists(mod_lower, true)) { if (cmDependsFortran::ModulesDiffer(mod_lower.c_str(), stamp.c_str(), compilerId.c_str())) { if (!cmSystemTools::CopyFileAlways(mod_lower, stamp)) { @@ -599,7 +583,7 @@ bool cmDependsFortran::ModulesDiffer(const char* modFile, A mod file is a binary file. However, looking into both generated bar.mod files with a hex editor shows that they differ only before a sequence linefeed-zero (0x0A 0x00) - which is located some bytes in front of the absoulte path to the source + which is located some bytes in front of the absolute path to the source file. sun: diff --git a/Source/cmDependsFortran.h b/Source/cmDependsFortran.h index ccf267b..bee9804 100644 --- a/Source/cmDependsFortran.h +++ b/Source/cmDependsFortran.h @@ -64,7 +64,7 @@ protected: const std::string& file, std::ostream& makeDepends, std::ostream& internalDepends) override; - // Actually write the depenencies to the streams. + // Actually write the dependencies to the streams. bool WriteDependenciesReal(const char* obj, cmFortranSourceInfo const& info, std::string const& mod_dir, const char* stamp_dir, std::ostream& makeDepends, diff --git a/Source/cmDependsJavaParserHelper.cxx b/Source/cmDependsJavaParserHelper.cxx index f227cf2..02db119 100644 --- a/Source/cmDependsJavaParserHelper.cxx +++ b/Source/cmDependsJavaParserHelper.cxx @@ -10,6 +10,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <utility> int cmDependsJava_yyparse(yyscan_t yyscanner); @@ -22,7 +23,7 @@ cmDependsJavaParserHelper::cmDependsJavaParserHelper() CurrentClass tl; tl.Name = "*"; - this->ClassStack.push_back(tl); + this->ClassStack.push_back(std::move(tl)); } cmDependsJavaParserHelper::~cmDependsJavaParserHelper() @@ -175,7 +176,7 @@ void cmDependsJavaParserHelper::StartClass(const char* cls) { CurrentClass cl; cl.Name = cls; - this->ClassStack.push_back(cl); + this->ClassStack.push_back(std::move(cl)); this->CurrentDepth++; } diff --git a/Source/cmDocumentation.cxx b/Source/cmDocumentation.cxx index 0c96860..2dfba04 100644 --- a/Source/cmDocumentation.cxx +++ b/Source/cmDocumentation.cxx @@ -213,7 +213,7 @@ bool cmDocumentation::CheckOptions(int argc, const char* const* argv, if (argc == 1) { RequestedHelpItem help; help.HelpType = cmDocumentation::Usage; - this->RequestedHelpItems.push_back(help); + this->RequestedHelpItems.push_back(std::move(help)); return true; } @@ -352,7 +352,7 @@ bool cmDocumentation::CheckOptions(int argc, const char* const* argv, if (help.HelpType != None) { // This is a help option. See if there is a file name given. result = true; - this->RequestedHelpItems.push_back(help); + this->RequestedHelpItems.push_back(std::move(help)); } } return result; diff --git a/Source/cmDocumentationSection.cxx b/Source/cmDocumentationSection.cxx index c47f33e..439da1b 100644 --- a/Source/cmDocumentationSection.cxx +++ b/Source/cmDocumentationSection.cxx @@ -6,7 +6,7 @@ void cmDocumentationSection::Append(const char* data[][2]) { int i = 0; while (data[i][1]) { - this->Entries.push_back(cmDocumentationEntry(data[i][0], data[i][1])); + this->Entries.emplace_back(data[i][0], data[i][1]); data += 1; } } @@ -16,7 +16,7 @@ void cmDocumentationSection::Prepend(const char* data[][2]) std::vector<cmDocumentationEntry> tmp; int i = 0; while (data[i][1]) { - tmp.push_back(cmDocumentationEntry(data[i][0], data[i][1])); + tmp.emplace_back(data[i][0], data[i][1]); data += 1; } this->Entries.insert(this->Entries.begin(), tmp.begin(), tmp.end()); @@ -24,5 +24,5 @@ void cmDocumentationSection::Prepend(const char* data[][2]) void cmDocumentationSection::Append(const char* n, const char* b) { - this->Entries.push_back(cmDocumentationEntry(n, b)); + this->Entries.emplace_back(n, b); } diff --git a/Source/cmDuration.cxx b/Source/cmDuration.cxx new file mode 100644 index 0000000..8ca5d8d --- /dev/null +++ b/Source/cmDuration.cxx @@ -0,0 +1,27 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#define CMDURATION_CPP +#include "cmDuration.h" + +template <typename T> +T cmDurationTo(const cmDuration& duration) +{ + /* This works because the comparison operators for duration rely on + * std::common_type. + * So for example duration<int>::max() gets promoted to a duration<double>, + * which can then be safely compared. + */ + if (duration >= std::chrono::duration<T>::max()) { + return std::chrono::duration<T>::max().count(); + } + if (duration <= std::chrono::duration<T>::min()) { + return std::chrono::duration<T>::min().count(); + } + // Ensure number of seconds by defining ratio<1> + return std::chrono::duration_cast<std::chrono::duration<T, std::ratio<1>>>( + duration) + .count(); +} + +template int cmDurationTo<int>(const cmDuration&); +template unsigned int cmDurationTo<unsigned int>(const cmDuration&); diff --git a/Source/cmDuration.h b/Source/cmDuration.h new file mode 100644 index 0000000..6df1455 --- /dev/null +++ b/Source/cmDuration.h @@ -0,0 +1,24 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include <chrono> +#include <ratio> + +typedef std::chrono::duration<double, std::ratio<1>> cmDuration; + +/* + * This function will return number of seconds in the requested type T. + * + * A duration_cast from duration<double> to duration<T> will not yield what + * one might expect if the double representation does not fit into type T. + * This function aims to safely convert, by clamping the double value between + * the permissible valid values for T. + */ +template <typename T> +T cmDurationTo(const cmDuration& duration); + +#ifndef CMDURATION_CPP +extern template int cmDurationTo<int>(const cmDuration&); +extern template unsigned int cmDurationTo<unsigned int>(const cmDuration&); +#endif diff --git a/Source/cmELF.cxx b/Source/cmELF.cxx index 76374b2..77ccd30 100644 --- a/Source/cmELF.cxx +++ b/Source/cmELF.cxx @@ -547,8 +547,7 @@ cmELF::DynamicEntryList cmELFInternalImpl<Types>::GetDynamicEntries() // Copy into public array result.reserve(this->DynamicSectionEntries.size()); for (ELF_Dyn& dyn : this->DynamicSectionEntries) { - result.push_back( - std::pair<unsigned long, unsigned long>(dyn.d_tag, dyn.d_un.d_val)); + result.emplace_back(dyn.d_tag, dyn.d_un.d_val); } return result; diff --git a/Source/cmExecProgramCommand.cxx b/Source/cmExecProgramCommand.cxx index 88e085d..49f880c 100644 --- a/Source/cmExecProgramCommand.cxx +++ b/Source/cmExecProgramCommand.cxx @@ -81,7 +81,7 @@ bool cmExecProgramCommand::InitialPass(std::vector<std::string> const& args, std::string output; bool result = true; if (args.size() - count == 2) { - cmSystemTools::MakeDirectory(args[1].c_str()); + cmSystemTools::MakeDirectory(args[1]); result = cmExecProgramCommand::RunCommand(command.c_str(), output, retVal, args[1].c_str(), verbose); } else { @@ -149,7 +149,7 @@ bool cmExecProgramCommand::RunCommand(const char* command, std::string& output, if (quoted.find(command)) { std::string cmd = quoted.match(1); std::string args = quoted.match(2); - if (!cmSystemTools::FileExists(cmd.c_str())) { + if (!cmSystemTools::FileExists(cmd)) { shortCmd = cmd; } else if (!cmSystemTools::GetShortPath(cmd.c_str(), shortCmd)) { cmSystemTools::Error("GetShortPath failed for ", cmd.c_str()); diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx index 39e774e..679a648 100644 --- a/Source/cmExecuteProcessCommand.cxx +++ b/Source/cmExecuteProcessCommand.cxx @@ -157,7 +157,7 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args, } } - if (!this->Makefile->CanIWriteThisFile(output_file.c_str())) { + if (!this->Makefile->CanIWriteThisFile(output_file)) { std::string e = "attempted to output into a file: " + output_file + " into a source directory."; this->SetError(e); diff --git a/Source/cmExpandedCommandArgument.cxx b/Source/cmExpandedCommandArgument.cxx index 0bea65f..1c0a721 100644 --- a/Source/cmExpandedCommandArgument.cxx +++ b/Source/cmExpandedCommandArgument.cxx @@ -24,6 +24,11 @@ bool cmExpandedCommandArgument::WasQuoted() const return this->Quoted; } +bool cmExpandedCommandArgument::operator==(const char* value) const +{ + return this->Value == value; +} + bool cmExpandedCommandArgument::operator==(std::string const& value) const { return this->Value == value; diff --git a/Source/cmExpandedCommandArgument.h b/Source/cmExpandedCommandArgument.h index fe86528..302e8db 100644 --- a/Source/cmExpandedCommandArgument.h +++ b/Source/cmExpandedCommandArgument.h @@ -24,6 +24,7 @@ public: bool WasQuoted() const; + bool operator==(const char* value) const; bool operator==(std::string const& value) const; bool empty() const; diff --git a/Source/cmExportBuildAndroidMKGenerator.cxx b/Source/cmExportBuildAndroidMKGenerator.cxx index 5e2cd53..817b5d9 100644 --- a/Source/cmExportBuildAndroidMKGenerator.cxx +++ b/Source/cmExportBuildAndroidMKGenerator.cxx @@ -8,6 +8,7 @@ #include <utility> #include "cmGeneratorExpression.h" +#include "cmGeneratorExpressionDAGChecker.h" #include "cmGeneratorTarget.h" #include "cmLinkItem.h" #include "cmLocalGenerator.h" @@ -48,8 +49,7 @@ void cmExportBuildAndroidMKGenerator::GenerateImportTargetCode( os << "LOCAL_MODULE := "; os << targetName << "\n"; os << "LOCAL_SRC_FILES := "; - std::string path = - cmSystemTools::ConvertToOutputPath(target->GetFullPath().c_str()); + std::string path = cmSystemTools::ConvertToOutputPath(target->GetFullPath()); os << path << "\n"; } @@ -102,12 +102,21 @@ void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties( os << "LOCAL_CPP_FEATURES += "; os << (property.second) << "\n"; } else if (property.first == "INTERFACE_LINK_LIBRARIES") { + // evaluate any generator expressions with the current + // build type of the makefile + cmGeneratorExpression ge; + cmGeneratorExpressionDAGChecker dagChecker( + target->GetName(), "INTERFACE_LINK_LIBRARIES", nullptr, nullptr); + std::unique_ptr<cmCompiledGeneratorExpression> cge = + ge.Parse(property.second); + std::string evaluated = cge->Evaluate( + target->GetLocalGenerator(), config, false, target, &dagChecker); // need to look at list in pi->second and see if static or shared // FindTargetToLink // target->GetLocalGenerator()->FindGeneratorTargetToUse() // then add to LOCAL_CPPFLAGS std::vector<std::string> libraries; - cmSystemTools::ExpandListArgument(property.second, libraries); + cmSystemTools::ExpandListArgument(evaluated, libraries); std::string staticLibs; std::string sharedLibs; std::string ldlibs; @@ -123,12 +132,6 @@ void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties( staticLibs += " " + lib; } } else { - // evaluate any generator expressions with the current - // build type of the makefile - cmGeneratorExpression ge; - std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(lib); - std::string evaluated = - cge->Evaluate(target->GetLocalGenerator(), config); bool relpath = false; if (type == cmExportBuildAndroidMKGenerator::INSTALL) { relpath = lib.substr(0, 3) == "../"; @@ -136,12 +139,12 @@ void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties( // check for full path or if it already has a -l, or // in the case of an install check for relative paths // if it is full or a link library then use string directly - if (cmSystemTools::FileIsFullPath(evaluated) || - evaluated.substr(0, 2) == "-l" || relpath) { - ldlibs += " " + evaluated; + if (cmSystemTools::FileIsFullPath(lib) || + lib.substr(0, 2) == "-l" || relpath) { + ldlibs += " " + lib; // if it is not a path and does not have a -l then add -l - } else if (!evaluated.empty()) { - ldlibs += " -l" + evaluated; + } else if (!lib.empty()) { + ldlibs += " -l" + lib; } } } diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index bb1dda3..f7aa6e8 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -228,7 +228,7 @@ void cmExportBuildFileGenerator::HandleMissingTarget( missingTarget += dependee->GetExportName(); link_libs += missingTarget; - missingTargets.push_back(missingTarget); + missingTargets.push_back(std::move(missingTarget)); return; } // We are not appending, so all exported targets should be diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx index 9913129..c8a727d 100644 --- a/Source/cmExportCommand.cxx +++ b/Source/cmExportCommand.cxx @@ -92,8 +92,8 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args, } // Get the file to write. - if (cmSystemTools::FileIsFullPath(fname.c_str())) { - if (!this->Makefile->CanIWriteThisFile(fname.c_str())) { + if (cmSystemTools::FileIsFullPath(fname)) { + if (!this->Makefile->CanIWriteThisFile(fname)) { std::ostringstream e; e << "FILE option given filename \"" << fname << "\" which is in the source tree.\n"; @@ -205,7 +205,7 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args, std::vector<std::string> configurationTypes; this->Makefile->GetConfigurations(configurationTypes); if (configurationTypes.empty()) { - configurationTypes.push_back(""); + configurationTypes.emplace_back(); } for (std::string const& ct : configurationTypes) { ebfg->AddConfiguration(ct); @@ -346,10 +346,10 @@ void cmExportCommand::StorePackageRegistryDir(std::string const& package, fname += "/.cmake/packages/"; fname += package; #endif - cmSystemTools::MakeDirectory(fname.c_str()); + cmSystemTools::MakeDirectory(fname); fname += "/"; fname += hash; - if (!cmSystemTools::FileExists(fname.c_str())) { + if (!cmSystemTools::FileExists(fname)) { cmGeneratedFileStream entry(fname.c_str(), true); if (entry) { entry << content << "\n"; diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 7f0cb97..434abdc 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -183,7 +183,7 @@ bool cmExportFileGenerator::PopulateInterfaceLinkLibrariesProperty( return false; } -static bool isSubDirectory(const char* a, const char* b) +static bool isSubDirectory(std::string const& a, std::string const& b) { return (cmSystemTools::ComparePath(a, b) || cmSystemTools::IsSubDirectory(a, b)); @@ -195,13 +195,15 @@ static bool checkInterfaceDirs(const std::string& prepro, { const char* installDir = target->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX"); - const char* topSourceDir = target->GetLocalGenerator()->GetSourceDirectory(); - const char* topBinaryDir = target->GetLocalGenerator()->GetBinaryDirectory(); + std::string const& topSourceDir = + target->GetLocalGenerator()->GetSourceDirectory(); + std::string const& topBinaryDir = + target->GetLocalGenerator()->GetBinaryDirectory(); std::vector<std::string> parts; cmGeneratorExpression::Split(prepro, parts); - const bool inSourceBuild = strcmp(topSourceDir, topBinaryDir) == 0; + const bool inSourceBuild = topSourceDir == topBinaryDir; bool hadFatalError = false; @@ -231,10 +233,10 @@ static bool checkInterfaceDirs(const std::string& prepro, hadFatalError = true; } } - if (cmHasLiteralPrefix(li.c_str(), "${_IMPORT_PREFIX}")) { + if (cmHasLiteralPrefix(li, "${_IMPORT_PREFIX}")) { continue; } - if (!cmSystemTools::FileIsFullPath(li.c_str())) { + if (!cmSystemTools::FileIsFullPath(li)) { /* clang-format off */ e << "Target \"" << target->GetName() << "\" " << prop << " property contains relative path:\n" @@ -242,9 +244,9 @@ static bool checkInterfaceDirs(const std::string& prepro, /* clang-format on */ target->GetLocalGenerator()->IssueMessage(messageType, e.str()); } - bool inBinary = isSubDirectory(li.c_str(), topBinaryDir); - bool inSource = isSubDirectory(li.c_str(), topSourceDir); - if (isSubDirectory(li.c_str(), installDir)) { + bool inBinary = isSubDirectory(li, topBinaryDir); + bool inSource = isSubDirectory(li, topSourceDir); + if (isSubDirectory(li, installDir)) { // The include directory is inside the install tree. If the // install tree is not inside the source tree or build tree then // fall through to the checks below that the include directory is not @@ -317,7 +319,7 @@ static void prefixItems(std::string& exportDirs) for (std::string const& e : entries) { exportDirs += sep; sep = ";"; - if (!cmSystemTools::FileIsFullPath(e.c_str()) && + if (!cmSystemTools::FileIsFullPath(e) && e.find("${_IMPORT_PREFIX}") == std::string::npos) { exportDirs += "${_IMPORT_PREFIX}/"; } @@ -591,7 +593,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/cmExportInstallAndroidMKGenerator.h b/Source/cmExportInstallAndroidMKGenerator.h index 3165982..91554ee 100644 --- a/Source/cmExportInstallAndroidMKGenerator.h +++ b/Source/cmExportInstallAndroidMKGenerator.h @@ -22,7 +22,7 @@ class cmInstallExportGenerator; * cmExportInstallAndroidMKGenerator generates files exporting targets from * install an installation tree. The files are placed in a temporary * location for installation by cmInstallExportGenerator. The file format - * is for the ndk build system and is a makefile fragment specifing prebuilt + * is for the ndk build system and is a makefile fragment specifying prebuilt * libraries to the ndk build system. * * This is used to implement the INSTALL(EXPORT_ANDROID_MK) command. diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index 9b65e9e..954b561 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -185,12 +185,12 @@ void cmExportInstallFileGenerator::GenerateImportPrefix(std::ostream& os) os << "# Compute the installation prefix relative to this file.\n" << "get_filename_component(_IMPORT_PREFIX" << " \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n"; - if (cmHasLiteralPrefix(absDestS.c_str(), "/lib/") || - cmHasLiteralPrefix(absDestS.c_str(), "/lib64/") || - cmHasLiteralPrefix(absDestS.c_str(), "/libx32/") || - cmHasLiteralPrefix(absDestS.c_str(), "/usr/lib/") || - cmHasLiteralPrefix(absDestS.c_str(), "/usr/lib64/") || - cmHasLiteralPrefix(absDestS.c_str(), "/usr/libx32/")) { + if (cmHasLiteralPrefix(absDestS, "/lib/") || + cmHasLiteralPrefix(absDestS, "/lib64/") || + cmHasLiteralPrefix(absDestS, "/libx32/") || + cmHasLiteralPrefix(absDestS, "/usr/lib/") || + cmHasLiteralPrefix(absDestS, "/usr/lib64/") || + cmHasLiteralPrefix(absDestS, "/usr/libx32/")) { // Handle "/usr move" symlinks created by some Linux distros. /* clang-format off */ os << @@ -370,7 +370,7 @@ void cmExportInstallFileGenerator::SetImportLocationProperty( // Construct the installed location of the target. std::string dest = itgen->GetDestination(config); std::string value; - if (!cmSystemTools::FileIsFullPath(dest.c_str())) { + if (!cmSystemTools::FileIsFullPath(dest)) { // The target is installed relative to the installation prefix. value = "${_IMPORT_PREFIX}/"; } @@ -439,7 +439,7 @@ void cmExportInstallFileGenerator::HandleMissingTarget( missingTarget += dependee->GetExportName(); link_libs += missingTarget; - missingTargets.push_back(missingTarget); + missingTargets.push_back(std::move(missingTarget)); } else { // All exported targets should be known here and should be unique. // This is probably user-error. 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..5cc6442 100644 --- a/Source/cmExternalMakefileProjectGenerator.h +++ b/Source/cmExternalMakefileProjectGenerator.h @@ -17,7 +17,7 @@ class cmMakefile; * cmExternalMakefileProjectGenerator is a base class for generators * for "external makefile based projects", i.e. IDE projects which work * an already existing makefiles. - * See cmGlobalKdevelopGenerator as an example. + * See cmExtraEclipseCDT4Generator as an example. * After the makefiles have been generated by one of the Makefile * generators, the Generate() method is called and this generator * can iterate over the local generators and/or projects to produce the @@ -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..4b95140 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -5,7 +5,6 @@ #include <map> #include <ostream> #include <set> -#include <string.h> #include <utility> #include "cmAlgorithms.h" @@ -225,7 +224,7 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile( } const std::string& relative = cmSystemTools::RelativePath( - it.second[0]->GetSourceDirectory(), listFile.c_str()); + it.second[0]->GetSourceDirectory(), listFile); std::vector<std::string> splitted; cmSystemTools::SplitPath(relative, splitted, false); // Split filename from path @@ -296,8 +295,7 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile( case cmStateEnums::GLOBAL_TARGET: { // Only add the global targets from CMAKE_BINARY_DIR, // not from the subdirs - if (strcmp(lg->GetCurrentBinaryDirectory(), - lg->GetBinaryDirectory()) == 0) { + if (lg->GetCurrentBinaryDirectory() == lg->GetBinaryDirectory()) { this->AppendTarget(xml, targetName, nullptr, make.c_str(), lg, compiler.c_str(), makeArgs); } @@ -345,8 +343,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(); @@ -372,28 +369,23 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile( continue; } - // check whether it is a C/C++ implementation file + // check whether it is a C/C++/CUDA implementation file bool isCFile = false; std::string lang = s->GetLanguage(); - if (lang == "C" || lang == "CXX") { + if (lang == "C" || lang == "CXX" || lang == "CUDA") { 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(); // Check file position relative to project root dir. - const std::string& relative = cmSystemTools::RelativePath( - (*lg).GetSourceDirectory(), fullPath.c_str()); + const std::string& relative = + cmSystemTools::RelativePath(lg->GetSourceDirectory(), fullPath); // Do not add this file if it has ".." in relative path and // if CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES variable is on. const bool excludeExternal = - cmSystemTools::IsOn((*lg).GetMakefile()->GetSafeDefinition( + cmSystemTools::IsOn(lg->GetMakefile()->GetSafeDefinition( "CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES")); if (excludeExternal && (relative.find("..") != std::string::npos)) { @@ -422,7 +414,7 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile( // C/C++ source files, // replacing the file name extension with ".h" and checks whether such a // file exists. If it does, it is inserted into the map of files. - // A very similar version of that code exists also in the kdevelop + // A very similar version of that code exists also in the CodeLite // project generator. for (std::string const& fileName : cFiles) { std::string headerBasename = cmSystemTools::GetFilenamePath(fileName); @@ -439,7 +431,7 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile( break; } - if (cmSystemTools::FileExists(hname.c_str())) { + if (cmSystemTools::FileExists(hname)) { allFiles[hname].Targets = allFiles[fileName].Targets; break; } @@ -648,6 +640,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..4dbaa3f 100644 --- a/Source/cmExtraCodeLiteGenerator.cxx +++ b/Source/cmExtraCodeLiteGenerator.cxx @@ -64,8 +64,8 @@ void cmExtraCodeLiteGenerator::Generate() const cmMakefile* mf = it.second[0]->GetMakefile(); this->ConfigName = GetConfigurationName(mf); - if (strcmp(it.second[0]->GetCurrentBinaryDirectory(), - it.second[0]->GetBinaryDirectory()) == 0) { + if (it.second[0]->GetCurrentBinaryDirectory() == + it.second[0]->GetBinaryDirectory()) { workspaceOutputDir = it.second[0]->GetCurrentBinaryDirectory(); workspaceProjectName = it.second[0]->GetProjectName(); workspaceSourcePath = it.second[0]->GetSourceDirectory(); @@ -127,8 +127,8 @@ std::vector<std::string> cmExtraCodeLiteGenerator::CreateProjectsByTarget( std::string filename = outputDir + "/" + targetName + ".project"; retval.push_back(targetName); // Make the project file relative to the workspace - std::string relafilename = cmSystemTools::RelativePath( - this->WorkspacePath.c_str(), filename.c_str()); + std::string relafilename = + cmSystemTools::RelativePath(this->WorkspacePath, filename); std::string visualname = targetName; switch (type) { case cmStateEnums::SHARED_LIBRARY: @@ -167,8 +167,7 @@ std::vector<std::string> cmExtraCodeLiteGenerator::CreateProjectsByProjectMaps( std::string filename = outputDir + "/" + projectName + ".project"; // Make the project file relative to the workspace - filename = cmSystemTools::RelativePath(this->WorkspacePath.c_str(), - filename.c_str()); + filename = cmSystemTools::RelativePath(this->WorkspacePath, filename); // create a project file this->CreateProjectFile(it.second); @@ -198,9 +197,6 @@ 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(); - std::string projectType; switch (gt->GetType()) { case cmStateEnums::EXECUTABLE: { @@ -228,24 +224,18 @@ std::string cmExtraCodeLiteGenerator::CollectSourceFiles( gt->GetSourceFiles(sources, makefile->GetSafeDefinition("CMAKE_BUILD_TYPE")); for (cmSourceFile* s : sources) { - // check whether it is a C/C++ implementation file - bool isCFile = false; - 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; - } - } - } - + // check whether it is a source or a include file // then put it accordingly into one of the two containers - if (isCFile) { - cFiles[s->GetFullPath()] = s; - } else { - otherFiles.insert(s->GetFullPath()); + switch (cmSystemTools::GetFileFormat(s->GetExtension().c_str())) { + case cmSystemTools::C_FILE_FORMAT: + case cmSystemTools::CXX_FILE_FORMAT: + case cmSystemTools::CUDA_FILE_FORMAT: + case cmSystemTools::FORTRAN_FILE_FORMAT: { + cFiles[s->GetFullPath()] = s; + } break; + default: { + otherFiles.insert(s->GetFullPath()); + } } } } @@ -309,7 +299,7 @@ void cmExtraCodeLiteGenerator::FindMatchingHeaderfiles( // files to the project. It does that by iterating over all source files, // replacing the file name extension with ".h" and checks whether such a // file exists. If it does, it is inserted into the map of files. - // A very similar version of that code exists also in the kdevelop + // A very similar version of that code exists also in the CodeBlocks // project generator. for (auto const& sit : cFiles) { std::string headerBasename = cmSystemTools::GetFilenamePath(sit.first); @@ -327,7 +317,7 @@ void cmExtraCodeLiteGenerator::FindMatchingHeaderfiles( break; } - if (cmSystemTools::FileExists(hname.c_str())) { + if (cmSystemTools::FileExists(hname)) { otherFiles.insert(hname); break; } @@ -344,8 +334,7 @@ void cmExtraCodeLiteGenerator::CreateFoldersAndFiles( size_t numOfEndEl = 0; for (std::string const& cFile : cFiles) { - std::string frelapath = - cmSystemTools::RelativePath(projectPath.c_str(), cFile.c_str()); + std::string frelapath = cmSystemTools::RelativePath(projectPath, cFile); cmsys::SystemTools::SplitPath(frelapath, components, false); components.pop_back(); // erase last member -> it is file, not folder components.erase(components.begin()); // erase "root" @@ -483,8 +472,7 @@ void cmExtraCodeLiteGenerator::CreateProjectSourceEntries( std::string outputPath = mf->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH"); std::string relapath; if (!outputPath.empty()) { - relapath = cmSystemTools::RelativePath(this->WorkspacePath.c_str(), - outputPath.c_str()); + relapath = cmSystemTools::RelativePath(this->WorkspacePath, outputPath); xml.Attribute("OutputFile", relapath + "/$(ProjectName)"); } else { xml.Attribute("OutputFile", "$(IntermediateDirectory)/$(ProjectName)"); @@ -685,7 +673,11 @@ std::string cmExtraCodeLiteGenerator::GetSingleFileBuildCommand( std::string generator = mf->GetSafeDefinition("CMAKE_GENERATOR"); if (generator == "Unix Makefiles" || generator == "MinGW Makefiles") { std::ostringstream ss; - ss << make << " -f$(ProjectPath)/Makefile $(CurrentFileName).cpp.o"; +#if defined(_WIN32) + ss << make << " -f$(ProjectPath)/Makefile -B $(CurrentFileFullName).obj"; +#else + ss << make << " -f$(ProjectPath)/Makefile -B $(CurrentFileFullName).o"; +#endif buildCommand = ss.str(); } return buildCommand; diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx index a200385..258c9ca 100644 --- a/Source/cmExtraEclipseCDT4Generator.cxx +++ b/Source/cmExtraEclipseCDT4Generator.cxx @@ -413,7 +413,7 @@ void cmExtraEclipseCDT4Generator::CreateProjectFile() this->AppendLinkedResource(xml, sourceLinkedResourceName, this->GetEclipsePath(linkSourceDirectory), LinkToFolder); - this->SrcLinkedResources.push_back(sourceLinkedResourceName); + this->SrcLinkedResources.push_back(std::move(sourceLinkedResourceName)); } } @@ -498,7 +498,7 @@ void cmExtraEclipseCDT4Generator::CreateLinksForTargets(cmXMLWriter& xml) // Add the file to the list of sources. std::string const& source = sf->GetFullPath(); cmSourceGroup* sourceGroup = - makefile->FindSourceGroup(source.c_str(), sourceGroups); + makefile->FindSourceGroup(source, sourceGroups); sourceGroup->AssignSource(sf); } diff --git a/Source/cmExtraKateGenerator.cxx b/Source/cmExtraKateGenerator.cxx index 79cc6ef..7a83e41 100644 --- a/Source/cmExtraKateGenerator.cxx +++ b/Source/cmExtraKateGenerator.cxx @@ -81,12 +81,12 @@ void cmExtraKateGenerator::WriteTargets(const cmLocalGenerator* lg, const std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM"); const std::string makeArgs = mf->GetSafeDefinition("CMAKE_KATE_MAKE_ARGUMENTS"); - const char* homeOutputDir = lg->GetBinaryDirectory(); + std::string const& homeOutputDir = lg->GetBinaryDirectory(); /* clang-format off */ fout << "\t\"build\": {\n" - "\t\t\"directory\": \"" << lg->GetBinaryDirectory() << "\",\n" + "\t\t\"directory\": \"" << homeOutputDir << "\",\n" "\t\t\"default_target\": \"all\",\n" "\t\t\"clean_target\": \"clean\",\n"; /* clang-format on */ @@ -195,13 +195,13 @@ void cmExtraKateGenerator::AppendTarget(cmGeneratedFileStream& fout, const std::string& make, const std::string& makeArgs, const std::string& path, - const char* homeOutputDir) const + const std::string& homeOutputDir) const { static char JsonSep = ' '; fout << "\t\t\t" << JsonSep << "{\"name\":\"" << target << "\", " "\"build_cmd\":\"" - << make << " -C \\\"" << (this->UseNinja ? homeOutputDir : path.c_str()) + << make << " -C \\\"" << (this->UseNinja ? homeOutputDir : path) << "\\\" " << makeArgs << " " << target << "\"}\n"; JsonSep = ','; @@ -228,14 +228,14 @@ std::string cmExtraKateGenerator::GenerateFilesString( { std::string s = lg->GetSourceDirectory(); s += "/.git"; - if (cmSystemTools::FileExists(s.c_str())) { - return std::string("\"git\": 1 "); + if (cmSystemTools::FileExists(s)) { + return "\"git\": 1 "; } s = lg->GetSourceDirectory(); s += "/.svn"; - if (cmSystemTools::FileExists(s.c_str())) { - return std::string("\"svn\": 1 "); + if (cmSystemTools::FileExists(s)) { + return "\"svn\": 1 "; } s = lg->GetSourceDirectory(); diff --git a/Source/cmExtraKateGenerator.h b/Source/cmExtraKateGenerator.h index 9716fe7..a4355f0 100644 --- a/Source/cmExtraKateGenerator.h +++ b/Source/cmExtraKateGenerator.h @@ -31,7 +31,8 @@ private: cmGeneratedFileStream& fout) const; void AppendTarget(cmGeneratedFileStream& fout, const std::string& target, const std::string& make, const std::string& makeArgs, - const std::string& path, const char* homeOutputDir) const; + const std::string& path, + const std::string& homeOutputDir) const; std::string GenerateFilesString(const cmLocalGenerator* lg) const; std::string GetPathBasename(const std::string& path) const; diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx index 73a9c85..46dcaf6 100644 --- a/Source/cmExtraSublimeTextGenerator.cxx +++ b/Source/cmExtraSublimeTextGenerator.cxx @@ -188,8 +188,7 @@ void cmExtraSublimeTextGenerator::AppendAllTargets( case cmStateEnums::GLOBAL_TARGET: { // Only add the global targets from CMAKE_BINARY_DIR, // not from the subdirs - if (strcmp(lg->GetCurrentBinaryDirectory(), - lg->GetBinaryDirectory()) == 0) { + if (lg->GetCurrentBinaryDirectory() == lg->GetBinaryDirectory()) { this->AppendTarget(fout, targetName, lg, nullptr, make.c_str(), makefile, compiler.c_str(), sourceFileFlags, false); @@ -257,6 +256,8 @@ void cmExtraSublimeTextGenerator::AppendTarget( std::string flagsString = this->ComputeFlagsForObject(sourceFile, lg, target); std::string definesString = this->ComputeDefines(sourceFile, lg, target); + std::string includesString = + this->ComputeIncludes(sourceFile, lg, target); flags.clear(); cmsys::RegularExpression flagRegex; // Regular expression to extract compiler flags from a string @@ -264,7 +265,8 @@ void cmExtraSublimeTextGenerator::AppendTarget( const char* regexString = "(^|[ ])-[DIOUWfgs][^= ]+(=\\\"[^\"]+\\\"|=[^\"][^ ]+)?"; flagRegex.compile(regexString); - std::string workString = flagsString + " " + definesString; + std::string workString = + flagsString + " " + definesString + " " + includesString; while (flagRegex.find(workString)) { std::string::size_type start = flagRegex.start(); if (workString[start] == ' ') { @@ -351,20 +353,19 @@ std::string cmExtraSublimeTextGenerator::ComputeFlagsForObject( lg->GetTargetCompileFlags(gtgt, config, language, flags); - // Add include directory flags. - { - std::vector<std::string> includes; - lg->GetIncludeDirectories(includes, gtgt, language, config); - std::string includeFlags = lg->GetIncludeFlags(includes, gtgt, language, - true); // full include paths - lg->AppendFlags(flags, includeFlags); + // Add source file specific flags. + cmGeneratorExpressionInterpreter genexInterpreter(lg, gtgt, config, + gtgt->GetName(), language); + + const std::string COMPILE_FLAGS("COMPILE_FLAGS"); + if (const char* cflags = source->GetProperty(COMPILE_FLAGS)) { + lg->AppendFlags(flags, genexInterpreter.Evaluate(cflags, COMPILE_FLAGS)); } - // Add source file specific flags. - if (const char* cflags = source->GetProperty("COMPILE_FLAGS")) { - cmGeneratorExpression ge; - const char* processed = ge.Parse(cflags)->Evaluate(lg, config); - lg->AppendFlags(flags, processed); + const std::string COMPILE_OPTIONS("COMPILE_OPTIONS"); + if (const char* coptions = source->GetProperty(COMPILE_OPTIONS)) { + lg->AppendCompileOptions( + flags, genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS)); } return flags; @@ -380,6 +381,8 @@ std::string cmExtraSublimeTextGenerator::ComputeDefines( cmMakefile* makefile = lg->GetMakefile(); const std::string& language = source->GetLanguage(); const std::string& config = makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); + cmGeneratorExpressionInterpreter genexInterpreter( + lg, target, config, target->GetName(), language); // Add the export symbol definition for shared library objects. if (const char* exportMacro = target->GetExportMacro()) { @@ -388,11 +391,17 @@ std::string cmExtraSublimeTextGenerator::ComputeDefines( // Add preprocessor definitions for this target and configuration. lg->AddCompileDefinitions(defines, target, config, language); - lg->AppendDefines(defines, source->GetProperty("COMPILE_DEFINITIONS")); - { - std::string defPropName = "COMPILE_DEFINITIONS_"; - defPropName += cmSystemTools::UpperCase(config); - lg->AppendDefines(defines, source->GetProperty(defPropName)); + const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS"); + if (const char* compile_defs = source->GetProperty(COMPILE_DEFINITIONS)) { + lg->AppendDefines( + defines, genexInterpreter.Evaluate(compile_defs, COMPILE_DEFINITIONS)); + } + + std::string defPropName = "COMPILE_DEFINITIONS_"; + defPropName += cmSystemTools::UpperCase(config); + if (const char* config_compile_defs = source->GetProperty(defPropName)) { + lg->AppendDefines(defines, genexInterpreter.Evaluate(config_compile_defs, + COMPILE_DEFINITIONS)); } std::string definesString; @@ -400,3 +409,54 @@ std::string cmExtraSublimeTextGenerator::ComputeDefines( return definesString; } + +std::string cmExtraSublimeTextGenerator::ComputeIncludes( + cmSourceFile* source, cmLocalGenerator* lg, cmGeneratorTarget* target) + +{ + std::vector<std::string> includes; + cmMakefile* makefile = lg->GetMakefile(); + const std::string& language = source->GetLanguage(); + const std::string& config = makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); + cmGeneratorExpressionInterpreter genexInterpreter( + lg, target, config, target->GetName(), language); + + // Add include directories for this source file + const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES"); + if (const char* cincludes = source->GetProperty(INCLUDE_DIRECTORIES)) { + lg->AppendIncludeDirectories( + includes, genexInterpreter.Evaluate(cincludes, INCLUDE_DIRECTORIES), + *source); + } + + // Add include directory flags. + lg->GetIncludeDirectories(includes, target, language, config); + + std::string includesString = + lg->GetIncludeFlags(includes, target, language, true, false, config); + + return includesString; +} + +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..bc158f6 100644 --- a/Source/cmExtraSublimeTextGenerator.h +++ b/Source/cmExtraSublimeTextGenerator.h @@ -65,6 +65,12 @@ private: std::string ComputeDefines(cmSourceFile* source, cmLocalGenerator* lg, cmGeneratorTarget* gtgt); + std::string ComputeIncludes(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..d3dcc01 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. @@ -207,14 +183,14 @@ bool cmFileCommand::HandleWriteCommand(std::vector<std::string> const& args, i++; // Get rid of subcommand std::string fileName = *i; - if (!cmsys::SystemTools::FileIsFullPath(i->c_str())) { + if (!cmsys::SystemTools::FileIsFullPath(*i)) { fileName = this->Makefile->GetCurrentSourceDirectory(); fileName += "/" + *i; } i++; - if (!this->Makefile->CanIWriteThisFile(fileName.c_str())) { + if (!this->Makefile->CanIWriteThisFile(fileName)) { std::string e = "attempted to write a file: " + fileName + " into a source directory."; this->SetError(e); @@ -222,7 +198,7 @@ bool cmFileCommand::HandleWriteCommand(std::vector<std::string> const& args, return false; } std::string dir = cmSystemTools::GetFilenamePath(fileName); - cmSystemTools::MakeDirectory(dir.c_str()); + cmSystemTools::MakeDirectory(dir); mode_t mode = 0; @@ -282,7 +258,7 @@ bool cmFileCommand::HandleReadCommand(std::vector<std::string> const& args) argHelper.Parse(&args, nullptr); std::string fileName = fileNameArg.GetString(); - if (!cmsys::SystemTools::FileIsFullPath(fileName.c_str())) { + if (!cmsys::SystemTools::FileIsFullPath(fileName)) { fileName = this->Makefile->GetCurrentSourceDirectory(); fileName += "/" + fileNameArg.GetString(); } @@ -398,7 +374,7 @@ bool cmFileCommand::HandleStringsCommand(std::vector<std::string> const& args) // Get the file to read. std::string fileName = args[1]; - if (!cmsys::SystemTools::FileIsFullPath(fileName.c_str())) { + if (!cmsys::SystemTools::FileIsFullPath(fileName)) { fileName = this->Makefile->GetCurrentSourceDirectory(); fileName += "/" + args[1]; } @@ -824,7 +800,7 @@ bool cmFileCommand::HandleGlobCommand(std::vector<std::string> const& args, } cmsys::Glob::GlobMessages globMessages; - if (!cmsys::SystemTools::FileIsFullPath(i->c_str())) { + if (!cmsys::SystemTools::FileIsFullPath(*i)) { std::string expr = this->Makefile->GetCurrentSourceDirectory(); // Handle script mode if (!expr.empty()) { @@ -908,19 +884,19 @@ bool cmFileCommand::HandleMakeDirectoryCommand( std::string expr; for (; i != args.end(); ++i) { const std::string* cdir = &(*i); - if (!cmsys::SystemTools::FileIsFullPath(i->c_str())) { + if (!cmsys::SystemTools::FileIsFullPath(*i)) { expr = this->Makefile->GetCurrentSourceDirectory(); expr += "/" + *i; cdir = &expr; } - if (!this->Makefile->CanIWriteThisFile(cdir->c_str())) { + if (!this->Makefile->CanIWriteThisFile(*cdir)) { std::string e = "attempted to create a directory: " + *cdir + " into a source directory."; this->SetError(e); cmSystemTools::SetFatalErrorOccured(); return false; } - if (!cmSystemTools::MakeDirectory(cdir->c_str())) { + if (!cmSystemTools::MakeDirectory(*cdir)) { std::string error = "problem creating directory: " + *cdir; this->SetError(error); return false; @@ -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()); @@ -1340,7 +1294,7 @@ bool cmFileCopier::CheckValue(std::string const& arg) this->Files.push_back(arg); break; case DoingDestination: - if (arg.empty() || cmSystemTools::FileIsFullPath(arg.c_str())) { + if (arg.empty() || cmSystemTools::FileIsFullPath(arg)) { this->Destination = arg; } else { this->Destination = this->Makefile->GetCurrentBinaryDirectory(); @@ -1349,7 +1303,7 @@ bool cmFileCopier::CheckValue(std::string const& arg) this->Doing = DoingNone; break; case DoingFilesFromDir: - if (cmSystemTools::FileIsFullPath(arg.c_str())) { + if (cmSystemTools::FileIsFullPath(arg)) { this->FilesFromDir = arg; } else { this->FilesFromDir = this->Makefile->GetCurrentSourceDirectory(); @@ -1366,7 +1320,7 @@ bool cmFileCopier::CheckValue(std::string const& arg) std::string regex = "/"; regex += cmsys::Glob::PatternToRegex(arg, false); regex += "$"; - this->MatchRules.push_back(MatchRule(regex)); + this->MatchRules.emplace_back(regex); this->CurrentMatchRule = &*(this->MatchRules.end() - 1); if (this->CurrentMatchRule->Regex.is_valid()) { this->Doing = DoingNone; @@ -1378,7 +1332,7 @@ bool cmFileCopier::CheckValue(std::string const& arg) } } break; case DoingRegex: - this->MatchRules.push_back(MatchRule(arg)); + this->MatchRules.emplace_back(arg); this->CurrentMatchRule = &*(this->MatchRules.end() - 1); if (this->CurrentMatchRule->Regex.is_valid()) { this->Doing = DoingNone; @@ -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::FileExists(destination)) { + if (!cmSystemTools::MakeDirectory(destination, default_dir_mode)) { std::string errstring = "cannot create directory: " + destination + ". Maybe need administrative privileges."; this->FileCommand->SetError(errstring); @@ -2318,22 +2293,21 @@ bool cmFileCommand::HandleRelativePathCommand( const std::string& directoryName = args[2]; const std::string& fileName = args[3]; - if (!cmSystemTools::FileIsFullPath(directoryName.c_str())) { + if (!cmSystemTools::FileIsFullPath(directoryName)) { std::string errstring = "RELATIVE_PATH must be passed a full path to the directory: " + directoryName; this->SetError(errstring); return false; } - if (!cmSystemTools::FileIsFullPath(fileName.c_str())) { + if (!cmSystemTools::FileIsFullPath(fileName)) { std::string errstring = "RELATIVE_PATH must be passed a full path to the file: " + fileName; this->SetError(errstring); return false; } - std::string res = - cmSystemTools::RelativePath(directoryName.c_str(), fileName.c_str()); + std::string res = cmSystemTools::RelativePath(directoryName, fileName); this->Makefile->AddDefinition(outVar, res.c_str()); return true; } @@ -2347,12 +2321,12 @@ bool cmFileCommand::HandleRename(std::vector<std::string> const& args) // Compute full path for old and new names. std::string oldname = args[1]; - if (!cmsys::SystemTools::FileIsFullPath(oldname.c_str())) { + if (!cmsys::SystemTools::FileIsFullPath(oldname)) { oldname = this->Makefile->GetCurrentSourceDirectory(); oldname += "/" + args[1]; } std::string newname = args[2]; - if (!cmsys::SystemTools::FileIsFullPath(newname.c_str())) { + if (!cmsys::SystemTools::FileIsFullPath(newname)) { newname = this->Makefile->GetCurrentSourceDirectory(); newname += "/" + args[2]; } @@ -2383,7 +2357,7 @@ bool cmFileCommand::HandleRemove(std::vector<std::string> const& args, i++; // Get rid of subcommand for (; i != args.end(); ++i) { std::string fileName = *i; - if (!cmsys::SystemTools::FileIsFullPath(fileName.c_str())) { + if (!cmsys::SystemTools::FileIsFullPath(fileName)) { fileName = this->Makefile->GetCurrentSourceDirectory(); fileName += "/" + *i; } @@ -2425,7 +2399,7 @@ bool cmFileCommand::HandleCMakePathCommand( if (!nativePath) { cmSystemTools::ConvertToUnixSlashes(*j); } else { - *j = cmSystemTools::ConvertToOutputPath(j->c_str()); + *j = cmSystemTools::ConvertToOutputPath(*j); // remove double quotes in the path cmsys::String& s = *j; @@ -2626,6 +2600,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 +2658,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()) { @@ -2742,7 +2735,7 @@ bool cmFileCommand::HandleDownloadCommand(std::vector<std::string> const& args) // and the existing file already has the expected hash, then simply // return. // - if (cmSystemTools::FileExists(file.c_str()) && hash.get()) { + if (cmSystemTools::FileExists(file) && hash.get()) { std::string msg; std::string actualHash = hash->HashFile(file); if (actualHash == expectedHash) { @@ -2761,8 +2754,7 @@ bool cmFileCommand::HandleDownloadCommand(std::vector<std::string> const& args) // as we receive downloaded bits from curl... // std::string dir = cmSystemTools::GetFilenamePath(file); - if (!cmSystemTools::FileExists(dir.c_str()) && - !cmSystemTools::MakeDirectory(dir.c_str())) { + if (!cmSystemTools::FileExists(dir) && !cmSystemTools::MakeDirectory(dir)) { std::string errstring = "DOWNLOAD error: cannot create directory '" + dir + "' - Specify file by full path name and verify that you " "have directory creation and file write privileges."; @@ -2822,6 +2814,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 +2966,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 +3005,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 +3153,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/cmFilePathChecksum.h b/Source/cmFilePathChecksum.h index 48b5da0..30881ce 100644 --- a/Source/cmFilePathChecksum.h +++ b/Source/cmFilePathChecksum.h @@ -29,13 +29,13 @@ public: /// @brief Parent directories are empty cmFilePathChecksum(); - /// @brief Initilizes the parent directories manually + /// @brief Initializes the parent directories manually cmFilePathChecksum(std::string const& currentSrcDir, std::string const& currentBinDir, std::string const& projectSrcDir, std::string const& projectBinDir); - /// @brief Initilizes the parent directories from a makefile + /// @brief Initializes the parent directories from a makefile cmFilePathChecksum(cmMakefile* makefile); /// @brief Allows parent directories setup after construction diff --git a/Source/cmFindCommon.cxx b/Source/cmFindCommon.cxx index 8142962..4a467f3 100644 --- a/Source/cmFindCommon.cxx +++ b/Source/cmFindCommon.cxx @@ -314,7 +314,7 @@ void cmFindCommon::AddPathSuffix(std::string const& arg) } // Store the suffix. - this->SearchPathSuffixes.push_back(suffix); + this->SearchPathSuffixes.push_back(std::move(suffix)); } void AddTrailingSlash(std::string& s) @@ -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/cmFindLibraryCommand.cxx b/Source/cmFindLibraryCommand.cxx index 758da2c..02bae82 100644 --- a/Source/cmFindLibraryCommand.cxx +++ b/Source/cmFindLibraryCommand.cxx @@ -150,7 +150,7 @@ void cmFindLibraryCommand::AddArchitecturePath( if (use_dirX) { dirX += "/"; - this->SearchPaths.push_back(dirX); + this->SearchPaths.push_back(std::move(dirX)); } if (use_dir) { @@ -323,7 +323,7 @@ void cmFindLibraryHelper::AddName(std::string const& name) } regex += "$"; entry.Regex.compile(regex.c_str()); - this->Names.push_back(entry); + this->Names.push_back(std::move(entry)); } void cmFindLibraryHelper::SetName(std::string const& name) @@ -353,7 +353,7 @@ bool cmFindLibraryHelper::CheckDirectoryForName(std::string const& path, if (name.TryRaw) { this->TestPath = path; this->TestPath += name.Raw; - if (cmSystemTools::FileExists(this->TestPath.c_str(), true)) { + if (cmSystemTools::FileExists(this->TestPath, true)) { this->BestPath = cmSystemTools::CollapseFullPath(this->TestPath); cmSystemTools::ConvertToUnixSlashes(this->BestPath); return true; diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 5a72655..2f3a85b 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -225,7 +225,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args, std::set<std::string> optionalComponents; // Always search directly in a generated path. - this->SearchPathSuffixes.push_back(""); + this->SearchPathSuffixes.emplace_back(); // Parse the arguments. enum Doing @@ -523,7 +523,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args, config = cmSystemTools::LowerCase(n); config += "-config.cmake"; - this->Configs.push_back(config); + this->Configs.push_back(std::move(config)); } } @@ -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); } @@ -660,7 +660,7 @@ bool cmFindPackageCommand::HandlePackageMode() cmSystemTools::ConvertToUnixSlashes(dir); // Treat relative paths with respect to the current source dir. - if (!cmSystemTools::FileIsFullPath(dir.c_str())) { + if (!cmSystemTools::FileIsFullPath(dir)) { dir = "/" + dir; dir = this->Makefile->GetCurrentSourceDirectory() + dir; } @@ -1346,10 +1346,10 @@ bool cmFindPackageCommand::CheckPackageRegistryEntry(const std::string& fname, cmSearchPath& outPaths) { // Parse the content of one package registry entry. - if (cmSystemTools::FileIsFullPath(fname.c_str())) { + if (cmSystemTools::FileIsFullPath(fname)) { // The first line in the stream is the full path to a file or // directory containing the package. - if (cmSystemTools::FileExists(fname.c_str())) { + if (cmSystemTools::FileExists(fname)) { // The path exists. Look for the package here. if (!cmSystemTools::FileIsDirectory(fname)) { outPaths.AddPath(cmSystemTools::GetFilenamePath(fname)); @@ -1442,8 +1442,7 @@ bool cmFindPackageCommand::FindConfigFile(std::string const& dir, if (this->DebugMode) { fprintf(stderr, "Checking file [%s]\n", file.c_str()); } - if (cmSystemTools::FileExists(file.c_str(), true) && - this->CheckVersion(file)) { + if (cmSystemTools::FileExists(file, true) && this->CheckVersion(file)) { return true; } } @@ -1463,7 +1462,7 @@ bool cmFindPackageCommand::CheckVersion(std::string const& config_file) // Look for foo-config-version.cmake std::string version_file = version_file_base; version_file += "-version.cmake"; - if (!haveResult && cmSystemTools::FileExists(version_file.c_str(), true)) { + if (!haveResult && cmSystemTools::FileExists(version_file, true)) { result = this->CheckVersionFile(version_file, version); haveResult = true; } @@ -1471,7 +1470,7 @@ bool cmFindPackageCommand::CheckVersion(std::string const& config_file) // Look for fooConfigVersion.cmake version_file = version_file_base; version_file += "Version.cmake"; - if (!haveResult && cmSystemTools::FileExists(version_file.c_str(), true)) { + if (!haveResult && cmSystemTools::FileExists(version_file, true)) { result = this->CheckVersionFile(version_file, version); haveResult = true; } @@ -1484,7 +1483,7 @@ bool cmFindPackageCommand::CheckVersion(std::string const& config_file) ConfigFileInfo configFileInfo; configFileInfo.filename = config_file; configFileInfo.version = version; - this->ConsideredConfigs.push_back(configFileInfo); + this->ConsideredConfigs.push_back(std::move(configFileInfo)); return result; } diff --git a/Source/cmFindPathCommand.cxx b/Source/cmFindPathCommand.cxx index ea26410..38ff2ed 100644 --- a/Source/cmFindPathCommand.cxx +++ b/Source/cmFindPathCommand.cxx @@ -94,7 +94,7 @@ std::string cmFindPathCommand::FindHeaderInFramework(std::string const& file, std::string intPath = fpath; intPath += "/Headers/"; intPath += fileName; - if (cmSystemTools::FileExists(intPath.c_str())) { + if (cmSystemTools::FileExists(intPath)) { if (this->IncludeFileInPath) { return intPath; } @@ -128,7 +128,7 @@ std::string cmFindPathCommand::FindNormalHeader() for (std::string const& sp : this->SearchPaths) { tryPath = sp; tryPath += n; - if (cmSystemTools::FileExists(tryPath.c_str())) { + if (cmSystemTools::FileExists(tryPath)) { if (this->IncludeFileInPath) { return tryPath; } diff --git a/Source/cmFindProgramCommand.cxx b/Source/cmFindProgramCommand.cxx index 2059b3d..1c63428 100644 --- a/Source/cmFindProgramCommand.cxx +++ b/Source/cmFindProgramCommand.cxx @@ -22,7 +22,7 @@ struct cmFindProgramHelper this->Extensions.push_back(".exe"); #endif // Consider original name with no extensions. - this->Extensions.push_back(""); + this->Extensions.emplace_back(); } // List of valid extensions. 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/cmFortranParserImpl.cxx b/Source/cmFortranParserImpl.cxx index 81f1286..dd4f16b 100644 --- a/Source/cmFortranParserImpl.cxx +++ b/Source/cmFortranParserImpl.cxx @@ -17,14 +17,14 @@ bool cmFortranParser_s::FindIncludeFile(const char* dir, // If the file is a full path, include it directly. if (cmSystemTools::FileIsFullPath(includeName)) { fileName = includeName; - return cmSystemTools::FileExists(fileName.c_str(), true); + return cmSystemTools::FileExists(fileName, true); } // Check for the file in the directory containing the including // file. std::string fullName = dir; fullName += "/"; fullName += includeName; - if (cmSystemTools::FileExists(fullName.c_str(), true)) { + if (cmSystemTools::FileExists(fullName, true)) { fileName = fullName; return true; } @@ -34,7 +34,7 @@ bool cmFortranParser_s::FindIncludeFile(const char* dir, fullName = i; fullName += "/"; fullName += includeName; - if (cmSystemTools::FileExists(fullName.c_str(), true)) { + if (cmSystemTools::FileExists(fullName, true)) { fileName = fullName; return true; } diff --git a/Source/cmGeneratedFileStream.cxx b/Source/cmGeneratedFileStream.cxx index 6aa593c..c0a74a5 100644 --- a/Source/cmGeneratedFileStream.cxx +++ b/Source/cmGeneratedFileStream.cxx @@ -147,7 +147,7 @@ void cmGeneratedFileStreamBase::Open(const char* name) cmSystemTools::RemoveFile(this->TempName); std::string dir = cmSystemTools::GetFilenamePath(this->TempName); - cmSystemTools::MakeDirectory(dir.c_str()); + cmSystemTools::MakeDirectory(dir); } bool cmGeneratedFileStreamBase::Close() diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index 86991c1..64ec30d 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/Source/cmGeneratorExpression.cxx @@ -9,6 +9,7 @@ #include "assert.h" #include "cmAlgorithms.h" #include "cmGeneratorExpressionContext.h" +#include "cmGeneratorExpressionDAGChecker.h" #include "cmGeneratorExpressionEvaluator.h" #include "cmGeneratorExpressionLexer.h" #include "cmGeneratorExpressionParser.h" @@ -202,7 +203,7 @@ static void prefixItems(const std::string& content, std::string& result, for (std::string const& e : entries) { result += sep; sep = ";"; - if (!cmSystemTools::FileIsFullPath(e.c_str()) && + if (!cmSystemTools::FileIsFullPath(e) && cmGeneratorExpression::Find(e) != 0) { result += prefix; } @@ -385,3 +386,18 @@ void cmCompiledGeneratorExpression::GetMaxLanguageStandard( mapping = it->second; } } + +const char* cmGeneratorExpressionInterpreter::Evaluate( + const char* expression, const std::string& property) +{ + if (this->Target.empty()) { + return this->EvaluateExpression(expression); + } + + // Specify COMPILE_OPTIONS to DAGchecker, same semantic as COMPILE_FLAGS + cmGeneratorExpressionDAGChecker dagChecker( + this->Target, property == "COMPILE_FLAGS" ? "COMPILE_OPTIONS" : property, + nullptr, nullptr); + + return this->EvaluateExpression(expression, &dagChecker); +} diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h index cface0d..9fd53c6 100644 --- a/Source/cmGeneratorExpression.h +++ b/Source/cmGeneratorExpression.h @@ -153,4 +153,89 @@ private: bool EvaluateForBuildsystem; }; +class cmGeneratorExpressionInterpreter +{ + CM_DISABLE_COPY(cmGeneratorExpressionInterpreter) + +public: + cmGeneratorExpressionInterpreter(cmLocalGenerator* localGenerator, + cmGeneratorTarget* generatorTarget, + const std::string& config, + const std::string& target, + const std::string& lang) + : LocalGenerator(localGenerator) + , GeneratorTarget(generatorTarget) + , Config(config) + , Target(target) + , Language(lang) + { + } + cmGeneratorExpressionInterpreter(cmLocalGenerator* localGenerator, + cmGeneratorTarget* generatorTarget, + const std::string& config) + : cmGeneratorExpressionInterpreter(localGenerator, generatorTarget, config, + std::string(), std::string()) + { + } + + const char* Evaluate(const char* expression) + { + return this->EvaluateExpression(expression); + } + const char* Evaluate(const std::string& expression) + { + return this->Evaluate(expression.c_str()); + } + const char* Evaluate(const char* expression, const std::string& property); + const char* Evaluate(const std::string& expression, + const std::string& property) + { + return this->Evaluate(expression.c_str(), property); + } + +protected: + cmGeneratorExpression& GetGeneratorExpression() + { + return this->GeneratorExpression; + } + + cmCompiledGeneratorExpression& GetCompiledGeneratorExpression() + { + return *(this->CompiledGeneratorExpression); + } + + cmLocalGenerator* GetLocalGenerator() { return this->LocalGenerator; } + + cmGeneratorTarget* GetGeneratorTarget() { return this->GeneratorTarget; } + + const std::string& GetTargetName() const { return this->Target; } + const std::string& GetLanguage() const { return this->Language; } + + const char* EvaluateExpression( + const char* expression, + cmGeneratorExpressionDAGChecker* dagChecker = nullptr) + { + this->CompiledGeneratorExpression = + this->GeneratorExpression.Parse(expression); + + if (dagChecker == nullptr) { + return this->CompiledGeneratorExpression->Evaluate( + this->LocalGenerator, this->Config, false, this->GeneratorTarget); + } + + return this->CompiledGeneratorExpression->Evaluate( + this->LocalGenerator, this->Config, false, this->GeneratorTarget, + dagChecker, this->Language); + } + +private: + cmGeneratorExpression GeneratorExpression; + std::unique_ptr<cmCompiledGeneratorExpression> CompiledGeneratorExpression; + cmLocalGenerator* LocalGenerator = nullptr; + cmGeneratorTarget* GeneratorTarget = nullptr; + std::string Config; + std::string Target; + std::string Language; +}; + #endif diff --git a/Source/cmGeneratorExpressionEvaluationFile.cxx b/Source/cmGeneratorExpressionEvaluationFile.cxx index 87b6b34..c544141 100644 --- a/Source/cmGeneratorExpressionEvaluationFile.cxx +++ b/Source/cmGeneratorExpressionEvaluationFile.cxx @@ -13,6 +13,7 @@ #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmSourceFile.h" +#include "cmSourceFileLocationKind.h" #include "cmSystemTools.h" #include "cmake.h" @@ -102,7 +103,8 @@ void cmGeneratorExpressionEvaluationFile::CreateOutputFile( for (std::string const& le : enabledLanguages) { std::string name = this->OutputFileExpr->Evaluate( lg, config, false, nullptr, nullptr, nullptr, le); - cmSourceFile* sf = lg->GetMakefile()->GetOrCreateSource(name); + cmSourceFile* sf = lg->GetMakefile()->GetOrCreateSource( + name, false, cmSourceFileLocationKind::Known); sf->SetProperty("GENERATED", "1"); gg->SetFilenameTargetDepends( @@ -153,7 +155,7 @@ void cmGeneratorExpressionEvaluationFile::Generate(cmLocalGenerator* lg) lg->GetMakefile()->GetConfigurations(allConfigs); if (allConfigs.empty()) { - allConfigs.push_back(""); + allConfigs.emplace_back(); } std::vector<std::string> enabledLanguages; diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index c73d486..dbc6840 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -132,9 +132,8 @@ std::string GeneratorExpressionContent::EvaluateParameters( int counter = 1; for (; pit != pend; ++pit, ++counter) { if (acceptsArbitraryContent && counter == numExpected) { - std::string lastParam = this->ProcessArbitraryContent( - node, identifier, context, dagChecker, pit); - parameters.push_back(lastParam); + parameters.push_back(this->ProcessArbitraryContent( + node, identifier, context, dagChecker, pit)); return std::string(); } std::string parameter; @@ -148,7 +147,7 @@ std::string GeneratorExpressionContent::EvaluateParameters( return std::string(); } } - parameters.push_back(parameter); + parameters.push_back(std::move(parameter)); } } diff --git a/Source/cmGeneratorExpressionLexer.cxx b/Source/cmGeneratorExpressionLexer.cxx index 931fd4d..e37f165 100644 --- a/Source/cmGeneratorExpressionLexer.cxx +++ b/Source/cmGeneratorExpressionLexer.cxx @@ -12,8 +12,7 @@ static void InsertText(const char* upto, const char* c, std::vector<cmGeneratorExpressionToken>& result) { if (upto != c) { - result.push_back(cmGeneratorExpressionToken( - cmGeneratorExpressionToken::Text, upto, c - upto)); + result.emplace_back(cmGeneratorExpressionToken::Text, upto, c - upto); } } @@ -22,6 +21,12 @@ std::vector<cmGeneratorExpressionToken> cmGeneratorExpressionLexer::Tokenize( { std::vector<cmGeneratorExpressionToken> result; + if (input.find('$') == std::string::npos) { + result.push_back(cmGeneratorExpressionToken( + cmGeneratorExpressionToken::Text, input.c_str(), input.size())); + return result; + } + const char* c = input.c_str(); const char* upto = c; @@ -30,8 +35,8 @@ std::vector<cmGeneratorExpressionToken> cmGeneratorExpressionLexer::Tokenize( case '$': if (c[1] == '<') { InsertText(upto, c, result); - result.push_back(cmGeneratorExpressionToken( - cmGeneratorExpressionToken::BeginExpression, c, 2)); + result.emplace_back(cmGeneratorExpressionToken::BeginExpression, c, + 2); upto = c + 2; ++c; SawBeginExpression = true; @@ -39,21 +44,18 @@ std::vector<cmGeneratorExpressionToken> cmGeneratorExpressionLexer::Tokenize( break; case '>': InsertText(upto, c, result); - result.push_back(cmGeneratorExpressionToken( - cmGeneratorExpressionToken::EndExpression, c, 1)); + result.emplace_back(cmGeneratorExpressionToken::EndExpression, c, 1); upto = c + 1; SawGeneratorExpression = SawBeginExpression; break; case ':': InsertText(upto, c, result); - result.push_back(cmGeneratorExpressionToken( - cmGeneratorExpressionToken::ColonSeparator, c, 1)); + result.emplace_back(cmGeneratorExpressionToken::ColonSeparator, c, 1); upto = c + 1; break; case ',': InsertText(upto, c, result); - result.push_back(cmGeneratorExpressionToken( - cmGeneratorExpressionToken::CommaSeparator, c, 1)); + result.emplace_back(cmGeneratorExpressionToken::CommaSeparator, c, 1); upto = c + 1; break; default: diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index fea20ba..c1f1ee4 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -805,7 +805,7 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode const std::vector<std::string>& parameters, cmGeneratorExpressionContext* context, const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker* dagChecker) const override + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override { if (context->Language.empty()) { reportError( @@ -827,31 +827,15 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode return std::string(); } std::string genName = gg->GetName(); - if (genName.find("Visual Studio") != std::string::npos) { + if (genName.find("Makefiles") == std::string::npos && + genName.find("Ninja") == std::string::npos && + genName.find("Visual Studio") == std::string::npos && + genName.find("Xcode") == std::string::npos && + genName.find("Watcom WMake") == std::string::npos) { reportError(context, content->GetOriginalExpression(), - "$<COMPILE_LANGUAGE:...> may not be used with Visual Studio " - "generators."); + "$<COMPILE_LANGUAGE:...> not supported for this generator."); 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."); - return std::string(); - } - } else { - if (genName.find("Makefiles") == std::string::npos && - genName.find("Ninja") == std::string::npos && - genName.find("Watcom WMake") == std::string::npos) { - reportError( - context, content->GetOriginalExpression(), - "$<COMPILE_LANGUAGE:...> not supported for this generator."); - return std::string(); - } - } if (parameters.empty()) { return context->Language; } @@ -963,7 +947,8 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode "Target name not supported."); return std::string(); } - if (propertyName == "ALIASED_TARGET") { + static const std::string propALIASED_TARGET = "ALIASED_TARGET"; + if (propertyName == propALIASED_TARGET) { if (context->LG->GetMakefile()->IsAlias(targetName)) { if (cmGeneratorTarget* tgt = context->LG->FindGeneratorTargetToUse(targetName)) { @@ -1035,7 +1020,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. @@ -1090,8 +1075,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(POPULATE_INTERFACE_PROPERTY_NAME) // Note that the above macro terminates with an else - /* else */ if (cmHasLiteralPrefix(propertyName.c_str(), - "COMPILE_DEFINITIONS_")) { + /* else */ if (cmHasLiteralPrefix(propertyName, "COMPILE_DEFINITIONS_")) { cmPolicies::PolicyStatus polSt = context->LG->GetPolicyStatus(cmPolicies::CMP0043); if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) { @@ -1443,7 +1427,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/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 103d034..e9b6daf 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -445,7 +445,7 @@ void cmGeneratorTarget::ComputeObjectMapping() std::vector<std::string> configs; this->Makefile->GetConfigurations(configs); if (configs.empty()) { - configs.push_back(""); + configs.emplace_back(); } for (std::string const& c : configs) { std::vector<cmSourceFile const*> sourceFiles; @@ -842,7 +842,7 @@ static bool processSources( return contextDependent; } - if (!targetName.empty() && !cmSystemTools::FileIsFullPath(src.c_str())) { + if (!targetName.empty() && !cmSystemTools::FileIsFullPath(src)) { std::ostringstream err; if (!targetName.empty()) { err << "Target \"" << targetName @@ -1101,8 +1101,7 @@ void cmGeneratorTarget::ComputeKindedSources(KindedSources& files, } // Save this classified source file in the result vector. - SourceAndKind entry = { sf, kind }; - files.Sources.push_back(entry); + files.Sources.push_back({ sf, kind }); } if (!badObjLib.empty()) { @@ -1143,7 +1142,7 @@ void cmGeneratorTarget::ComputeAllConfigSources() const AllConfigSource acs; acs.Source = src.Source; acs.Kind = src.Kind; - this->AllConfigSources.push_back(acs); + this->AllConfigSources.push_back(std::move(acs)); std::map<cmSourceFile const*, size_t>::value_type entry( src.Source, this->AllConfigSources.size() - 1); mi = index.insert(entry).first; @@ -1529,7 +1528,8 @@ std::string cmGeneratorTarget::GetAppBundleDirectory( ext = "app"; } fpath += ext; - if (shouldAddContentLevel(level) && !this->Makefile->PlatformIsAppleIos()) { + if (shouldAddContentLevel(level) && + !this->Makefile->PlatformIsAppleEmbedded()) { fpath += "/Contents"; if (shouldAddFullLevel(level)) { fpath += "/MacOS"; @@ -1559,7 +1559,8 @@ std::string cmGeneratorTarget::GetCFBundleDirectory( } } fpath += ext; - if (shouldAddContentLevel(level) && !this->Makefile->PlatformIsAppleIos()) { + if (shouldAddContentLevel(level) && + !this->Makefile->PlatformIsAppleEmbedded()) { fpath += "/Contents"; if (shouldAddFullLevel(level)) { fpath += "/MacOS"; @@ -1579,7 +1580,8 @@ std::string cmGeneratorTarget::GetFrameworkDirectory( ext = "framework"; } fpath += ext; - if (shouldAddFullLevel(level) && !this->Makefile->PlatformIsAppleIos()) { + if (shouldAddFullLevel(level) && + !this->Makefile->PlatformIsAppleEmbedded()) { fpath += "/Versions/"; fpath += this->GetFrameworkVersion(); } @@ -2110,7 +2112,7 @@ cmTargetTraceDependencies::cmTargetTraceDependencies(cmGeneratorTarget* target) std::vector<std::string> configs; this->Makefile->GetConfigurations(configs); if (configs.empty()) { - configs.push_back(""); + configs.emplace_back(); } std::set<cmSourceFile*> emitted; for (std::string const& c : configs) { @@ -2166,7 +2168,7 @@ void cmTargetTraceDependencies::Trace() // Queue the source needed to generate this file, if any. this->FollowName(sf->GetFullPath()); - // Queue dependencies added programatically by commands. + // Queue dependencies added programmatically by commands. this->FollowNames(sf->GetDepends()); // Queue custom command dependencies. @@ -2235,7 +2237,7 @@ bool cmTargetTraceDependencies::IsUtility(std::string const& dep) // If we find the target and the dep was given as a full path, // then make sure it was not a full path to something else, and // the fact that the name matched a target was just a coincidence. - if (cmSystemTools::FileIsFullPath(dep.c_str())) { + if (cmSystemTools::FileIsFullPath(dep)) { if (t->GetType() >= cmStateEnums::EXECUTABLE && t->GetType() <= cmStateEnums::MODULE_LIBRARY) { // This is really only for compatibility so we do not need to @@ -2303,7 +2305,7 @@ void cmTargetTraceDependencies::CheckCustomCommand(cmCustomCommand const& cc) std::set<std::string> emitted; this->Makefile->GetConfigurations(configs); if (configs.empty()) { - configs.push_back(""); + configs.emplace_back(); } for (std::string const& conf : configs) { this->FollowCommandDepends(cc, conf, emitted); @@ -2435,7 +2437,7 @@ static void processIncludeDirectories( std::string usedIncludes; for (std::string& entryInclude : entryIncludes) { - if (fromImported && !cmSystemTools::FileExists(entryInclude.c_str())) { + if (fromImported && !cmSystemTools::FileExists(entryInclude)) { std::ostringstream e; cmake::MessageType messageType = cmake::FATAL_ERROR; if (checkCMP0027) { @@ -2467,7 +2469,7 @@ static void processIncludeDirectories( return; } - if (!cmSystemTools::FileIsFullPath(entryInclude.c_str())) { + if (!cmSystemTools::FileIsFullPath(entryInclude)) { std::ostringstream e; bool noMessage = false; cmake::MessageType messageType = cmake::FATAL_ERROR; @@ -3004,7 +3006,7 @@ void cmGeneratorTarget::GetLibraryNames(std::string& name, std::string& soName, if (this->IsFrameworkOnApple()) { realName = prefix; - if (!this->Makefile->PlatformIsAppleIos()) { + if (!this->Makefile->PlatformIsAppleEmbedded()) { realName += "Versions/"; realName += this->GetFrameworkVersion(); realName += "/"; @@ -3538,7 +3540,7 @@ void checkPropertyConsistency(cmGeneratorTarget const* depender, for (std::string const& p : props) { std::string pname = cmSystemTools::HelpFileName(p); std::string pfile = pdir + pname + ".rst"; - if (cmSystemTools::FileExists(pfile.c_str(), true)) { + if (cmSystemTools::FileExists(pfile, true)) { std::ostringstream e; e << "Target \"" << dependee->GetName() << "\" has property \"" << p << "\" listed in its " << propName @@ -3614,13 +3616,13 @@ void cmGeneratorTarget::CheckPropertyCompatibility( const cmComputeLinkInformation::ItemVector& deps = info->GetItems(); std::set<std::string> emittedBools; - static std::string strBool = "COMPATIBLE_INTERFACE_BOOL"; + static const std::string strBool = "COMPATIBLE_INTERFACE_BOOL"; std::set<std::string> emittedStrings; - static std::string strString = "COMPATIBLE_INTERFACE_STRING"; + static const std::string strString = "COMPATIBLE_INTERFACE_STRING"; std::set<std::string> emittedMinNumbers; - static std::string strNumMin = "COMPATIBLE_INTERFACE_NUMBER_MIN"; + static const std::string strNumMin = "COMPATIBLE_INTERFACE_NUMBER_MIN"; std::set<std::string> emittedMaxNumbers; - static std::string strNumMax = "COMPATIBLE_INTERFACE_NUMBER_MAX"; + static const std::string strNumMax = "COMPATIBLE_INTERFACE_NUMBER_MAX"; for (auto const& dep : deps) { if (!dep.Target) { @@ -4198,7 +4200,7 @@ void cmGeneratorTarget::LookupLinkItems(std::vector<std::string> const& names, if (name == this->GetName() || name.empty()) { continue; } - items.push_back(cmLinkItem(name, this->FindTargetToLink(name))); + items.emplace_back(name, this->FindTargetToLink(name)); } } @@ -4985,7 +4987,7 @@ bool cmGeneratorTarget::GetConfigCommonSourceFiles( std::vector<std::string> configs; this->Makefile->GetConfigurations(configs); if (configs.empty()) { - configs.push_back(""); + configs.emplace_back(); } std::vector<std::string>::const_iterator it = configs.begin(); @@ -5133,7 +5135,12 @@ void cmGeneratorTarget::GetLanguages(std::set<std::string>& languages, std::string objLib = extObj->GetObjectLibrary(); if (cmGeneratorTarget* tgt = this->LocalGenerator->FindGeneratorTargetToUse(objLib)) { - objectLibraries.push_back(tgt); + auto const objLibIt = + std::find_if(objectLibraries.cbegin(), objectLibraries.cend(), + [tgt](cmGeneratorTarget* t) { return t == tgt; }); + if (objectLibraries.cend() == objLibIt) { + objectLibraries.push_back(tgt); + } } } } @@ -5149,7 +5156,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLanguages( std::set<std::string> languages; // Get languages used in our source files. this->GetLanguages(languages, config); - // Copy the set of langauges to the link implementation. + // Copy the set of languages to the link implementation. impl.Languages.insert(impl.Languages.begin(), languages.begin(), languages.end()); } @@ -5268,8 +5275,8 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( } // The entry is meant for this configuration. - impl.Libraries.push_back(cmLinkImplItem( - name, this->FindTargetToLink(name), *btIt, evaluated != *le)); + impl.Libraries.emplace_back(name, this->FindTargetToLink(name), *btIt, + evaluated != *le); } std::set<std::string> const& seenProps = cge->GetSeenTargetProperties(); @@ -5296,8 +5303,8 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( continue; } // Support OLD behavior for CMP0003. - impl.WrongConfigLibraries.push_back( - cmLinkItem(name, this->FindTargetToLink(name))); + impl.WrongConfigLibraries.emplace_back(name, + this->FindTargetToLink(name)); } } } diff --git a/Source/cmGetDirectoryPropertyCommand.cxx b/Source/cmGetDirectoryPropertyCommand.cxx index a8cf6ab..bf464d9 100644 --- a/Source/cmGetDirectoryPropertyCommand.cxx +++ b/Source/cmGetDirectoryPropertyCommand.cxx @@ -34,7 +34,7 @@ bool cmGetDirectoryPropertyCommand::InitialPass( } std::string sd = *i; // make sure the start dir is a full path - if (!cmSystemTools::FileIsFullPath(sd.c_str())) { + if (!cmSystemTools::FileIsFullPath(sd)) { sd = this->Makefile->GetCurrentSourceDirectory(); sd += "/"; sd += *i; diff --git a/Source/cmGetPropertyCommand.cxx b/Source/cmGetPropertyCommand.cxx index 4494c3e..1d812bd 100644 --- a/Source/cmGetPropertyCommand.cxx +++ b/Source/cmGetPropertyCommand.cxx @@ -206,7 +206,7 @@ bool cmGetPropertyCommand::HandleDirectoryMode() // Construct the directory name. Interpret relative paths with // respect to the current directory. std::string dir = this->Name; - if (!cmSystemTools::FileIsFullPath(dir.c_str())) { + if (!cmSystemTools::FileIsFullPath(dir)) { dir = this->Makefile->GetCurrentSourceDirectory(); dir += "/"; dir += this->Name; diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx index a31e415..270413c 100644 --- a/Source/cmGhsMultiTargetGenerator.cxx +++ b/Source/cmGhsMultiTargetGenerator.cxx @@ -486,14 +486,14 @@ void cmGhsMultiTargetGenerator::WriteSources( for (std::vector<cmSourceFile*>::const_iterator si = objectSources.begin(); si != objectSources.end(); ++si) { std::vector<cmSourceGroup> sourceGroups(this->Makefile->GetSourceGroups()); - char const* sourceFullPath = (*si)->GetFullPath().c_str(); + std::string const& sourceFullPath = (*si)->GetFullPath(); 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, - this->LocalGenerator->GetBinaryDirectory(), sgPath, + this->LocalGenerator->GetBinaryDirectory().c_str(), sgPath, GhsMultiGpj::SUBPROJECT, this->RelBuildFilePath); std::string fullSourcePath((*si)->GetFullPath()); @@ -604,11 +604,11 @@ std::string cmGhsMultiTargetGenerator::ComputeLongestObjectDirectory( dir_max += "/"; std::vector<cmSourceGroup> sourceGroups( localGhsMultiGenerator->GetMakefile()->GetSourceGroups()); - char const* const sourceFullPath = sourceFile->GetFullPath().c_str(); + std::string const& sourceFullPath = sourceFile->GetFullPath(); 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..c805b98 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -21,6 +21,7 @@ #include "cmComputeTargetDepends.h" #include "cmCustomCommand.h" #include "cmCustomCommandLines.h" +#include "cmDuration.h" #include "cmExportBuildFileGenerator.h" #include "cmExternalMakefileProjectGenerator.h" #include "cmGeneratedFileStream.h" @@ -33,7 +34,7 @@ #include "cmMakefile.h" #include "cmOutputConverter.h" #include "cmPolicies.h" -#include "cmQtAutoGeneratorInitializer.h" +#include "cmQtAutoGenInitializer.h" #include "cmSourceFile.h" #include "cmState.h" #include "cmStateDirectory.h" @@ -87,7 +88,7 @@ cmGlobalGenerator::cmGlobalGenerator(cmake* cm) this->InstallTargetEnabled = false; // how long to let try compiles run - this->TryCompileTimeout = 0; + this->TryCompileTimeout = cmDuration::zero(); this->ExtraGenerator = nullptr; this->CurrentConfigureMakefile = nullptr; @@ -111,6 +112,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 +282,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 { @@ -452,7 +510,7 @@ void cmGlobalGenerator::EnableLanguage( bool const readCMakeSystem = !mf->GetDefinition("CMAKE_SYSTEM_LOADED"); if (readCMakeSystem) { fpath += "/CMakeSystem.cmake"; - if (cmSystemTools::FileExists(fpath.c_str())) { + if (cmSystemTools::FileExists(fpath)) { mf->ReadListFile(fpath.c_str()); } } @@ -491,6 +549,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; @@ -558,7 +623,7 @@ void cmGlobalGenerator::EnableLanguage( // If the existing build tree was already configured with this // version of CMake then try to load the configured file first // to avoid duplicate compiler tests. - if (cmSystemTools::FileExists(fpath.c_str())) { + if (cmSystemTools::FileExists(fpath)) { if (!mf->ReadListFile(fpath.c_str())) { cmSystemTools::Error("Could not find cmake module file: ", fpath.c_str()); @@ -777,7 +842,7 @@ void cmGlobalGenerator::EnableLanguage( projectCompatibility += "/Modules/"; projectCompatibility += mf->GetSafeDefinition("PROJECT_NAME"); projectCompatibility += "Compatibility.cmake"; - if (cmSystemTools::FileExists(projectCompatibility.c_str())) { + if (cmSystemTools::FileExists(projectCompatibility)) { mf->ReadListFile(projectCompatibility.c_str()); } // Inform any extra generator of the new language. @@ -898,7 +963,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()) { @@ -1140,7 +1205,7 @@ void cmGlobalGenerator::Configure() f += this->CMakeInstance->GetCMakeFilesDirectory(); f += "/"; f += *log; - if (cmSystemTools::FileExists(f.c_str())) { + if (cmSystemTools::FileExists(f)) { msg << "\nSee also \"" << f << "\"."; } } @@ -1250,7 +1315,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 +1339,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 +1361,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 +1474,10 @@ bool cmGlobalGenerator::ComputeTargetDepends() return true; } -cmQtAutoGenDigestUPV cmGlobalGenerator::CreateQtAutoGeneratorsTargets() +std::vector<std::unique_ptr<cmQtAutoGenInitializer>> +cmGlobalGenerator::CreateQtAutoGenInitializers() { - cmQtAutoGenDigestUPV autogenDigests; + std::vector<std::unique_ptr<cmQtAutoGenInitializer>> autogenInits; #ifdef CMAKE_BUILD_WITH_CMAKE for (cmLocalGenerator* localGen : this->LocalGenerators) { @@ -1432,31 +1507,18 @@ cmQtAutoGenDigestUPV cmGlobalGenerator::CreateQtAutoGeneratorsTargets() } std::string qtVersionMajor = - cmQtAutoGeneratorInitializer::GetQtMajorVersion(target); + cmQtAutoGenInitializer::GetQtMajorVersion(target); // don't do anything if there is no Qt4 or Qt5Core (which contains moc) if (qtVersionMajor != "4" && qtVersionMajor != "5") { 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 cmQtAutoGenInitializer( + target, mocEnabled, uicEnabled, rccEnabled, qtVersionMajor)); } } - // Initialize autogen targets - for (const cmQtAutoGenDigestUP& digest : autogenDigests) { - cmQtAutoGeneratorInitializer::InitializeAutogenTarget(*digest); - } #endif - return autogenDigests; + return autogenInits; } cmLinkLineComputer* cmGlobalGenerator::CreateLinkLineComputer( @@ -1740,7 +1802,7 @@ int cmGlobalGenerator::Build(const std::string& /*unused*/, const std::string& target, std::string& output, const std::string& makeCommandCSTR, const std::string& config, bool clean, bool fast, - bool verbose, double timeout, + bool verbose, cmDuration timeout, cmSystemTools::OutputOption outputflag, std::vector<std::string> const& nativeOptions) { @@ -1824,12 +1886,22 @@ 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) { std::string makeCommand = cmSystemTools::GetCMakeCommand(); - makeCommand = cmSystemTools::ConvertToOutputPath(makeCommand.c_str()); + makeCommand = cmSystemTools::ConvertToOutputPath(makeCommand); makeCommand += " --build ."; if (!config.empty()) { makeCommand += " --config \""; @@ -2141,6 +2213,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 +2267,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)) { + 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,11 +2294,8 @@ 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); + singleLine.push_back("./CPackConfig.cmake"); + gti.CommandLines.push_back(std::move(singleLine)); if (this->GetPreinstallTargetName()) { gti.Depends.push_back(this->GetPreinstallTargetName()); } else { @@ -2183,111 +2305,131 @@ void cmGlobalGenerator::AddGlobalTarget_Package( gti.Depends.push_back(this->GetAllTargetName()); } } - if (cmSystemTools::FileExists(configFile.c_str())) { - targets.push_back(gti); - } + targets.push_back(std::move(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)) { + 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"); + singleLine.push_back("./CPackSourceConfig.cmake"); + singleLine.push_back(std::move(configFile)); + gti.CommandLines.push_back(std::move(singleLine)); + targets.push_back(std::move(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(std::move(singleLine)); + targets.push_back(std::move(gti)); } void cmGlobalGenerator::AddGlobalTarget_EditCache( std::vector<GlobalTargetInfo>& targets) { const char* editCacheTargetName = this->GetEditCacheTargetName(); - if (editCacheTargetName) { - GlobalTargetInfo gti; - gti.Name = editCacheTargetName; - cmCustomCommandLine singleLine; - - // Use generator preference for the edit_cache rule if it is defined. - std::string edit_cmd = this->GetEditCacheCommand(); - if (!edit_cmd.empty()) { - singleLine.push_back(edit_cmd); - singleLine.push_back("-H$(CMAKE_SOURCE_DIR)"); - singleLine.push_back("-B$(CMAKE_BINARY_DIR)"); - gti.Message = "Running CMake cache editor..."; - gti.UsesTerminal = true; - gti.CommandLines.push_back(singleLine); - } else { - singleLine.push_back(cmSystemTools::GetCMakeCommand()); - singleLine.push_back("-E"); - singleLine.push_back("echo"); - singleLine.push_back("No interactive CMake dialog available."); - gti.Message = "No interactive CMake dialog available..."; - gti.UsesTerminal = false; - gti.CommandLines.push_back(singleLine); - } + if (!editCacheTargetName) { + return; + } + GlobalTargetInfo gti; + gti.Name = editCacheTargetName; + cmCustomCommandLine singleLine; - targets.push_back(gti); + // Use generator preference for the edit_cache rule if it is defined. + std::string edit_cmd = this->GetEditCacheCommand(); + if (!edit_cmd.empty()) { + singleLine.push_back(std::move(edit_cmd)); + singleLine.push_back("-H$(CMAKE_SOURCE_DIR)"); + singleLine.push_back("-B$(CMAKE_BINARY_DIR)"); + gti.Message = "Running CMake cache editor..."; + gti.UsesTerminal = true; + } else { + singleLine.push_back(cmSystemTools::GetCMakeCommand()); + singleLine.push_back("-E"); + singleLine.push_back("echo"); + singleLine.push_back("No interactive CMake dialog available."); + gti.Message = "No interactive CMake dialog available..."; + gti.UsesTerminal = false; } + gti.CommandLines.push_back(std::move(singleLine)); + + targets.push_back(std::move(gti)); } void cmGlobalGenerator::AddGlobalTarget_RebuildCache( std::vector<GlobalTargetInfo>& targets) { const char* rebuildCacheTargetName = this->GetRebuildCacheTargetName(); - if (rebuildCacheTargetName) { - GlobalTargetInfo gti; - gti.Name = rebuildCacheTargetName; - gti.Message = "Running CMake to regenerate build system..."; - gti.UsesTerminal = true; - cmCustomCommandLine singleLine; - singleLine.push_back(cmSystemTools::GetCMakeCommand()); - singleLine.push_back("-H$(CMAKE_SOURCE_DIR)"); - singleLine.push_back("-B$(CMAKE_BINARY_DIR)"); - gti.CommandLines.push_back(singleLine); - targets.push_back(gti); + if (!rebuildCacheTargetName) { + return; } + GlobalTargetInfo gti; + gti.Name = rebuildCacheTargetName; + gti.Message = "Running CMake to regenerate build system..."; + gti.UsesTerminal = true; + cmCustomCommandLine singleLine; + singleLine.push_back(cmSystemTools::GetCMakeCommand()); + singleLine.push_back("-H$(CMAKE_SOURCE_DIR)"); + singleLine.push_back("-B$(CMAKE_BINARY_DIR)"); + gti.CommandLines.push_back(std::move(singleLine)); + targets.push_back(std::move(gti)); } void cmGlobalGenerator::AddGlobalTarget_Install( @@ -2315,7 +2457,7 @@ void cmGlobalGenerator::AddGlobalTarget_Install( gti.Name = "list_install_components"; gti.Message = ostr.str(); gti.UsesTerminal = false; - targets.push_back(gti); + targets.push_back(std::move(gti)); } std::string cmd = cmSystemTools::GetCMakeCommand(); GlobalTargetInfo gti; @@ -2369,7 +2511,7 @@ void cmGlobalGenerator::AddGlobalTarget_Install( localCmdLine.insert(localCmdLine.begin() + 1, "-DCMAKE_INSTALL_LOCAL_ONLY=1"); - gti.CommandLines.push_back(localCmdLine); + gti.CommandLines.push_back(std::move(localCmdLine)); targets.push_back(gti); } @@ -2385,7 +2527,7 @@ void cmGlobalGenerator::AddGlobalTarget_Install( stripCmdLine.insert(stripCmdLine.begin() + 1, "-DCMAKE_INSTALL_DO_STRIP=1"); - gti.CommandLines.push_back(stripCmdLine); + gti.CommandLines.push_back(std::move(stripCmdLine)); targets.push_back(gti); } } @@ -2467,7 +2609,7 @@ std::string cmGlobalGenerator::GenerateRuleFile( bool cmGlobalGenerator::ShouldStripResourcePath(cmMakefile* mf) const { - return mf->PlatformIsAppleIos(); + return mf->PlatformIsAppleEmbedded(); } std::string cmGlobalGenerator::GetSharedLibFlagsForLanguage( @@ -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" - }; + const char* reservedTargets[] = { "all", "ALL_BUILD", "help", + "install", "INSTALL", "preinstall", + "clean", "edit_cache", "rebuild_cache", + "ZERO_CHECK" }; - return std::find(cmArrayBegin(reservedTargets), cmArrayEnd(reservedTargets), - name) != cmArrayEnd(reservedTargets); + return std::find(cm::cbegin(reservedTargets), cm::cend(reservedTargets), + name) != cm::cend(reservedTargets); } void cmGlobalGenerator::SetExternalMakefileProjectGenerator( @@ -2713,7 +2854,7 @@ void cmGlobalGenerator::CheckRuleHashes(std::string const& pfile, // that if the feature is turned back on and the rule has // changed the file is still rebuilt. std::string fpath = cmSystemTools::CollapseFullPath(fname, home.c_str()); - if (cmSystemTools::FileExists(fpath.c_str())) { + if (cmSystemTools::FileExists(fpath)) { RuleHash hash; strncpy(hash.Data, line.c_str(), 32); this->RuleHashes[fname] = hash; @@ -2779,7 +2920,7 @@ void cmGlobalGenerator::WriteSummary(cmGeneratorTarget* target) Json::Value& lj_target_labels = lj_target["labels"] = Json::arrayValue; Json::Value& lj_sources = lj_root["sources"] = Json::arrayValue; - cmSystemTools::MakeDirectory(dir.c_str()); + cmSystemTools::MakeDirectory(dir); cmGeneratedFileStream fout(file.c_str()); std::vector<std::string> labels; @@ -2830,7 +2971,7 @@ void cmGlobalGenerator::WriteSummary(cmGeneratorTarget* target) std::vector<std::string> configs; target->Target->GetMakefile()->GetConfigurations(configs); if (configs.empty()) { - configs.push_back(""); + configs.emplace_back(); } for (std::string const& c : configs) { target->GetSourceFiles(sources, c); @@ -2925,7 +3066,7 @@ bool cmGlobalGenerator::GenerateCPackPropertiesFile() std::string path = this->CMakeInstance->GetHomeOutputDirectory(); path += "/CPackProperties.cmake"; - if (!cmSystemTools::FileExists(path.c_str()) && installedFiles.empty()) { + if (!cmSystemTools::FileExists(path) && installedFiles.empty()) { return true; } diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 18ca682..34ed5b0 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -14,8 +14,8 @@ #include <vector> #include "cmCustomCommandLines.h" +#include "cmDuration.h" #include "cmExportSetMap.h" -#include "cmQtAutoGenDigest.h" #include "cmStateSnapshot.h" #include "cmSystemTools.h" #include "cmTarget.h" @@ -33,6 +33,7 @@ class cmLinkLineComputer; class cmLocalGenerator; class cmMakefile; class cmOutputConverter; +class cmQtAutoGenInitializer; class cmSourceFile; class cmStateDirectory; class cmake; @@ -70,6 +71,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); @@ -157,11 +161,17 @@ public: const std::string& projectName, const std::string& targetName, std::string& output, const std::string& makeProgram, const std::string& config, bool clean, bool fast, bool verbose, - double timeout, cmSystemTools::OutputOption outputflag = - cmSystemTools::OUTPUT_NONE, + cmDuration timeout, cmSystemTools::OutputOption outputflag = + cmSystemTools::OUTPUT_NONE, 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, @@ -224,7 +234,7 @@ public: void EnableInstallTarget(); - int TryCompileTimeout; + cmDuration TryCompileTimeout; bool GetForceUnixPaths() const { return this->ForceUnixPaths; } bool GetToolSupportsColor() const { return this->ToolSupportsColor; } @@ -349,6 +359,10 @@ public: virtual bool IsIPOSupported() const { return false; } + /** Return whether the generator can import external visual studio project + using INCLUDE_EXTERNAL_MSPROJECT */ + virtual bool IsIncludeExternalMSProjectSupported() const { return false; } + /** Return whether the generator should use EFFECTIVE_PLATFORM_NAME. This is relevant for mixed macOS and iOS builds. */ virtual bool UseEffectivePlatformName(cmMakefile*) const { return false; } @@ -424,7 +438,8 @@ protected: virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const; // Qt auto generators - cmQtAutoGenDigestUPV CreateQtAutoGeneratorsTargets(); + std::vector<std::unique_ptr<cmQtAutoGenInitializer>> + CreateQtAutoGenInitializers(); std::string SelectMakeProgram(const std::string& makeProgram, const std::string& makeDefault = "") const; @@ -533,6 +548,8 @@ private: virtual void ForceLinkerLanguages(); + bool CheckTargetsForMissingSources() const; + void CreateLocalGenerators(); void CheckCompilerIdCompatibility(cmMakefile* mf, @@ -557,6 +574,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/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx index 788a179..946ed80 100644 --- a/Source/cmGlobalGhsMultiGenerator.cxx +++ b/Source/cmGlobalGhsMultiGenerator.cxx @@ -447,8 +447,8 @@ void cmGlobalGhsMultiGenerator::UpdateBuildFiles( this->TargetFolderBuildStreams.find(folderName)) { this->AddFilesUpToPath( GetBuildFileStream(), &this->TargetFolderBuildStreams, - this->GetCMakeInstance()->GetHomeOutputDirectory(), folderName, - GhsMultiGpj::PROJECT); + this->GetCMakeInstance()->GetHomeOutputDirectory().c_str(), + folderName, GhsMultiGpj::PROJECT); } std::vector<cmsys::String> splitPath = cmSystemTools::SplitString( cmGhsMultiTargetGenerator::GetRelBuildFileName(tgt)); diff --git a/Source/cmGlobalKdevelopGenerator.cxx b/Source/cmGlobalKdevelopGenerator.cxx deleted file mode 100644 index b1e630e..0000000 --- a/Source/cmGlobalKdevelopGenerator.cxx +++ /dev/null @@ -1,589 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmGlobalKdevelopGenerator.h" - -#include "cmGeneratedFileStream.h" -#include "cmGeneratorTarget.h" -#include "cmGlobalGenerator.h" -#include "cmLocalGenerator.h" -#include "cmMakefile.h" -#include "cmSourceFile.h" -#include "cmStateTypes.h" -#include "cmSystemTools.h" -#include "cmTarget.h" -#include "cmXMLWriter.h" -#include "cmake.h" - -#include "cmsys/Directory.hxx" -#include "cmsys/FStream.hxx" -#include <set> -#include <string.h> -#include <utility> - -cmGlobalKdevelopGenerator::cmGlobalKdevelopGenerator() - : cmExternalMakefileProjectGenerator() -{ -} - -cmExternalMakefileProjectGeneratorFactory* -cmGlobalKdevelopGenerator::GetFactory() -{ - static cmExternalMakefileProjectGeneratorSimpleFactory< - cmGlobalKdevelopGenerator> - factory("KDevelop3", "Generates KDevelop 3 project files."); - - if (factory.GetSupportedGlobalGenerators().empty()) { - factory.AddSupportedGlobalGenerator("Unix Makefiles"); -#ifdef CMAKE_USE_NINJA - factory.AddSupportedGlobalGenerator("Ninja"); -#endif - - factory.Aliases.push_back("KDevelop3"); - } - - return &factory; -} - -void cmGlobalKdevelopGenerator::Generate() -{ - // for each sub project in the project create - // a kdevelop project - for (auto const& it : this->GlobalGenerator->GetProjectMap()) { - std::string outputDir = it.second[0]->GetCurrentBinaryDirectory(); - std::string projectDir = it.second[0]->GetSourceDirectory(); - std::string projectName = it.second[0]->GetProjectName(); - std::string cmakeFilePattern("CMakeLists.txt;*.cmake;"); - std::string fileToOpen; - const std::vector<cmLocalGenerator*>& lgs = it.second; - // create the project.kdevelop.filelist file - if (!this->CreateFilelistFile(lgs, outputDir, projectDir, projectName, - cmakeFilePattern, fileToOpen)) { - cmSystemTools::Error("Can not create filelist file"); - return; - } - // try to find the name of an executable so we have something to - // run from kdevelop for now just pick the first executable found - std::string executable; - for (cmLocalGenerator* lg : lgs) { - std::vector<cmGeneratorTarget*> const& targets = - lg->GetGeneratorTargets(); - for (cmGeneratorTarget* target : targets) { - if (target->GetType() == cmStateEnums::EXECUTABLE) { - executable = target->GetLocation(""); - break; - } - } - if (!executable.empty()) { - break; - } - } - - // now create a project file - this->CreateProjectFile(outputDir, projectDir, projectName, executable, - cmakeFilePattern, fileToOpen); - } -} - -bool cmGlobalKdevelopGenerator::CreateFilelistFile( - const std::vector<cmLocalGenerator*>& lgs, const std::string& outputDir, - const std::string& projectDirIn, const std::string& projectname, - std::string& cmakeFilePattern, std::string& fileToOpen) -{ - std::string projectDir = projectDirIn + "/"; - std::string filename = outputDir + "/" + projectname + ".kdevelop.filelist"; - - std::set<std::string> files; - std::string tmp; - - std::vector<std::string> const& hdrExts = - this->GlobalGenerator->GetCMakeInstance()->GetHeaderExtensions(); - - for (cmLocalGenerator* lg : lgs) { - cmMakefile* makefile = lg->GetMakefile(); - const std::vector<std::string>& listFiles = makefile->GetListFiles(); - for (std::string const& listFile : listFiles) { - tmp = listFile; - cmSystemTools::ReplaceString(tmp, projectDir.c_str(), ""); - // make sure the file is part of this source tree - if ((tmp[0] != '/') && - (strstr(tmp.c_str(), cmake::GetCMakeFilesDirectoryPostSlash()) == - nullptr)) { - files.insert(tmp); - tmp = cmSystemTools::GetFilenameName(tmp); - // add all files which dont match the default - // */CMakeLists.txt;*cmake; to the file pattern - if ((tmp != "CMakeLists.txt") && - (strstr(tmp.c_str(), ".cmake") == nullptr)) { - cmakeFilePattern += tmp + ";"; - } - } - } - - // get all sources - const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets(); - for (cmGeneratorTarget* gt : targets) { - std::vector<cmSourceFile*> sources; - gt->GetSourceFiles(sources, gt->Target->GetMakefile()->GetSafeDefinition( - "CMAKE_BUILD_TYPE")); - for (cmSourceFile* sf : sources) { - tmp = sf->GetFullPath(); - std::string headerBasename = cmSystemTools::GetFilenamePath(tmp); - headerBasename += "/"; - headerBasename += cmSystemTools::GetFilenameWithoutExtension(tmp); - - cmSystemTools::ReplaceString(tmp, projectDir.c_str(), ""); - - if ((tmp[0] != '/') && - (strstr(tmp.c_str(), cmake::GetCMakeFilesDirectoryPostSlash()) == - nullptr) && - (cmSystemTools::GetFilenameExtension(tmp) != ".moc")) { - files.insert(tmp); - - // check if there's a matching header around - for (std::string const& hdrExt : hdrExts) { - std::string hname = headerBasename; - hname += "."; - hname += hdrExt; - if (cmSystemTools::FileExists(hname.c_str())) { - cmSystemTools::ReplaceString(hname, projectDir.c_str(), ""); - files.insert(hname); - break; - } - } - } - } - for (std::string const& listFile : listFiles) { - tmp = listFile; - cmSystemTools::ReplaceString(tmp, projectDir.c_str(), ""); - if ((tmp[0] != '/') && - (strstr(tmp.c_str(), cmake::GetCMakeFilesDirectoryPostSlash()) == - nullptr)) { - files.insert(tmp); - } - } - } - } - - // check if the output file already exists and read it - // insert all files which exist into the set of files - cmsys::ifstream oldFilelist(filename.c_str()); - if (oldFilelist) { - while (cmSystemTools::GetLineFromStream(oldFilelist, tmp)) { - if (tmp[0] == '/') { - continue; - } - std::string completePath = projectDir + tmp; - if (cmSystemTools::FileExists(completePath.c_str())) { - files.insert(tmp); - } - } - oldFilelist.close(); - } - - // now write the new filename - cmGeneratedFileStream fout(filename.c_str()); - if (!fout) { - return false; - } - - fileToOpen = ""; - for (std::string const& file : files) { - // get the full path to the file - tmp = cmSystemTools::CollapseFullPath(file, projectDir.c_str()); - // just select the first source file - if (fileToOpen.empty()) { - std::string ext = cmSystemTools::GetFilenameExtension(tmp); - if ((ext == ".c") || (ext == ".cc") || (ext == ".cpp") || - (ext == ".cxx") || (ext == ".C") || (ext == ".h") || - (ext == ".hpp")) { - fileToOpen = tmp; - } - } - // make it relative to the project dir - cmSystemTools::ReplaceString(tmp, projectDir.c_str(), ""); - // only put relative paths - if (!tmp.empty() && tmp[0] != '/') { - fout << tmp << "\n"; - } - } - return true; -} - -/* create the project file, if it already exists, merge it with the -existing one, otherwise create a new one */ -void cmGlobalKdevelopGenerator::CreateProjectFile( - const std::string& outputDir, const std::string& projectDir, - const std::string& projectname, const std::string& executable, - const std::string& cmakeFilePattern, const std::string& fileToOpen) -{ - this->Blacklist.clear(); - - std::string filename = outputDir + "/"; - filename += projectname + ".kdevelop"; - std::string sessionFilename = outputDir + "/"; - sessionFilename += projectname + ".kdevses"; - - if (cmSystemTools::FileExists(filename.c_str())) { - this->MergeProjectFiles(outputDir, projectDir, filename, executable, - cmakeFilePattern, fileToOpen, sessionFilename); - } else { - // add all subdirectories which are cmake build directories to the - // kdevelop blacklist so they are not monitored for added or removed files - // since this is handled by adding files to the cmake files - cmsys::Directory d; - if (d.Load(projectDir)) { - size_t numf = d.GetNumberOfFiles(); - for (unsigned int i = 0; i < numf; i++) { - std::string nextFile = d.GetFile(i); - if ((nextFile != ".") && (nextFile != "..")) { - std::string tmp = projectDir; - tmp += "/"; - tmp += nextFile; - if (cmSystemTools::FileIsDirectory(tmp)) { - tmp += "/CMakeCache.txt"; - if ((nextFile == "CMakeFiles") || - (cmSystemTools::FileExists(tmp.c_str()))) { - this->Blacklist.push_back(nextFile); - } - } - } - } - } - this->CreateNewProjectFile(outputDir, projectDir, filename, executable, - cmakeFilePattern, fileToOpen, sessionFilename); - } -} - -void cmGlobalKdevelopGenerator::MergeProjectFiles( - const std::string& outputDir, const std::string& projectDir, - const std::string& filename, const std::string& executable, - const std::string& cmakeFilePattern, const std::string& fileToOpen, - const std::string& sessionFilename) -{ - cmsys::ifstream oldProjectFile(filename.c_str()); - if (!oldProjectFile) { - this->CreateNewProjectFile(outputDir, projectDir, filename, executable, - cmakeFilePattern, fileToOpen, sessionFilename); - return; - } - - /* Read the existing project file (line by line), copy all lines - into the new project file, except the ones which can be reliably - set from contents of the CMakeLists.txt */ - std::string tmp; - std::vector<std::string> lines; - while (cmSystemTools::GetLineFromStream(oldProjectFile, tmp)) { - lines.push_back(tmp); - } - oldProjectFile.close(); - - cmGeneratedFileStream fout(filename.c_str()); - if (!fout) { - return; - } - - for (std::string const& l : lines) { - const char* line = l.c_str(); - // skip these tags as they are always replaced - if ((strstr(line, "<projectdirectory>") != nullptr) || - (strstr(line, "<projectmanagement>") != nullptr) || - (strstr(line, "<absoluteprojectpath>") != nullptr) || - (strstr(line, "<filelistdirectory>") != nullptr) || - (strstr(line, "<buildtool>") != nullptr) || - (strstr(line, "<builddir>") != nullptr)) { - continue; - } - - // output the line from the file if it is not one of the above tags - fout << l << "\n"; - // if this is the <general> tag output the stuff that goes in the - // general tag - if (strstr(line, "<general>")) { - fout << " <projectmanagement>KDevCustomProject</projectmanagement>\n"; - fout << " <projectdirectory>" << projectDir - << "</projectdirectory>\n"; // this one is important - fout << " <absoluteprojectpath>true</absoluteprojectpath>\n"; - // and this one - } - // inside kdevcustomproject the <filelistdirectory> must be put - if (strstr(line, "<kdevcustomproject>")) { - fout << " <filelistdirectory>" << outputDir - << "</filelistdirectory>\n"; - } - // buildtool and builddir go inside <build> - if (strstr(line, "<build>")) { - fout << " <buildtool>make</buildtool>\n"; - fout << " <builddir>" << outputDir << "</builddir>\n"; - } - } -} - -void cmGlobalKdevelopGenerator::CreateNewProjectFile( - const std::string& outputDir, const std::string& projectDir, - const std::string& filename, const std::string& executable, - const std::string& cmakeFilePattern, const std::string& fileToOpen, - const std::string& sessionFilename) -{ - cmGeneratedFileStream fout(filename.c_str()); - if (!fout) { - return; - } - cmXMLWriter xml(fout); - - // check for a version control system - bool hasSvn = cmSystemTools::FileExists((projectDir + "/.svn").c_str()); - bool hasCvs = cmSystemTools::FileExists((projectDir + "/CVS").c_str()); - - bool enableCxx = (this->GlobalGenerator->GetLanguageEnabled("C") || - this->GlobalGenerator->GetLanguageEnabled("CXX")); - bool enableFortran = this->GlobalGenerator->GetLanguageEnabled("Fortran"); - std::string primaryLanguage = "C++"; - if (enableFortran && !enableCxx) { - primaryLanguage = "Fortran77"; - } - - xml.StartDocument(); - xml.StartElement("kdevelop"); - xml.StartElement("general"); - - xml.Element("author", ""); - xml.Element("email", ""); - xml.Element("version", "$VERSION$"); - xml.Element("projectmanagement", "KDevCustomProject"); - xml.Element("primarylanguage", primaryLanguage); - xml.Element("ignoreparts"); - xml.Element("projectdirectory", projectDir); // this one is important - xml.Element("absoluteprojectpath", "true"); // and this one - - // setup additional languages - xml.StartElement("secondaryLanguages"); - if (enableFortran && enableCxx) { - xml.Element("language", "Fortran"); - } - if (enableCxx) { - xml.Element("language", "C"); - } - xml.EndElement(); - - if (hasSvn) { - xml.Element("versioncontrol", "kdevsubversion"); - } else if (hasCvs) { - xml.Element("versioncontrol", "kdevcvsservice"); - } - - xml.EndElement(); // general - xml.StartElement("kdevcustomproject"); - - xml.Element("filelistdirectory", outputDir); - - xml.StartElement("run"); - xml.Element("mainprogram", executable); - xml.Element("directoryradio", "custom"); - xml.Element("customdirectory", outputDir); - xml.Element("programargs", ""); - xml.Element("terminal", "false"); - xml.Element("autocompile", "true"); - xml.Element("envvars"); - xml.EndElement(); - - xml.StartElement("build"); - xml.Element("buildtool", "make"); // this one is important - xml.Element("builddir", outputDir); // and this one - xml.EndElement(); - - xml.StartElement("make"); - xml.Element("abortonerror", "false"); - xml.Element("numberofjobs", 1); - xml.Element("dontact", "false"); - xml.Element("makebin", this->GlobalGenerator->GetLocalGenerators()[0] - ->GetMakefile() - ->GetRequiredDefinition("CMAKE_MAKE_PROGRAM")); - xml.Element("selectedenvironment", "default"); - - xml.StartElement("environments"); - xml.StartElement("default"); - - xml.StartElement("envvar"); - xml.Attribute("value", 1); - xml.Attribute("name", "VERBOSE"); - xml.EndElement(); - - xml.StartElement("envvar"); - xml.Attribute("value", 1); - xml.Attribute("name", "CMAKE_NO_VERBOSE"); - xml.EndElement(); - - xml.EndElement(); // default - xml.EndElement(); // environments - xml.EndElement(); // make - - xml.StartElement("blacklist"); - for (std::string const& dir : this->Blacklist) { - xml.Element("path", dir); - } - xml.EndElement(); - - xml.EndElement(); // kdevcustomproject - - xml.StartElement("kdevfilecreate"); - xml.Element("filetypes"); - xml.StartElement("useglobaltypes"); - - xml.StartElement("type"); - xml.Attribute("ext", "ui"); - xml.EndElement(); - - xml.StartElement("type"); - xml.Attribute("ext", "cpp"); - xml.EndElement(); - - xml.StartElement("type"); - xml.Attribute("ext", "h"); - xml.EndElement(); - - xml.EndElement(); // useglobaltypes - xml.EndElement(); // kdevfilecreate - - xml.StartElement("kdevdoctreeview"); - xml.StartElement("projectdoc"); - xml.Element("userdocDir", "html/"); - xml.Element("apidocDir", "html/"); - xml.EndElement(); // projectdoc - xml.Element("ignoreqt_xml"); - xml.Element("ignoredoxygen"); - xml.Element("ignorekdocs"); - xml.Element("ignoretocs"); - xml.Element("ignoredevhelp"); - xml.EndElement(); // kdevdoctreeview; - - if (enableCxx) { - xml.StartElement("cppsupportpart"); - xml.StartElement("filetemplates"); - xml.Element("interfacesuffix", ".h"); - xml.Element("implementationsuffix", ".cpp"); - xml.EndElement(); // filetemplates - xml.EndElement(); // cppsupportpart - - xml.StartElement("kdevcppsupport"); - xml.StartElement("codecompletion"); - xml.Element("includeGlobalFunctions", "true"); - xml.Element("includeTypes", "true"); - xml.Element("includeEnums", "true"); - xml.Element("includeTypedefs", "false"); - xml.Element("automaticCodeCompletion", "true"); - xml.Element("automaticArgumentsHint", "true"); - xml.Element("automaticHeaderCompletion", "true"); - xml.Element("codeCompletionDelay", 250); - xml.Element("argumentsHintDelay", 400); - xml.Element("headerCompletionDelay", 250); - xml.EndElement(); // codecompletion - xml.Element("references"); - xml.EndElement(); // kdevcppsupport; - } - - if (enableFortran) { - xml.StartElement("kdevfortransupport"); - xml.StartElement("ftnchek"); - xml.Element("division", "false"); - xml.Element("extern", "false"); - xml.Element("declare", "false"); - xml.Element("pure", "false"); - xml.Element("argumentsall", "false"); - xml.Element("commonall", "false"); - xml.Element("truncationall", "false"); - xml.Element("usageall", "false"); - xml.Element("f77all", "false"); - xml.Element("portabilityall", "false"); - xml.Element("argumentsonly"); - xml.Element("commononly"); - xml.Element("truncationonly"); - xml.Element("usageonly"); - xml.Element("f77only"); - xml.Element("portabilityonly"); - xml.EndElement(); // ftnchek - xml.EndElement(); // kdevfortransupport; - } - - // set up file groups. maybe this can be used with the CMake SOURCE_GROUP() - // command - xml.StartElement("kdevfileview"); - xml.StartElement("groups"); - - xml.StartElement("group"); - xml.Attribute("pattern", cmakeFilePattern); - xml.Attribute("name", "CMake"); - xml.EndElement(); - - if (enableCxx) { - xml.StartElement("group"); - xml.Attribute("pattern", "*.h;*.hxx;*.hpp"); - xml.Attribute("name", "Header"); - xml.EndElement(); - - xml.StartElement("group"); - xml.Attribute("pattern", "*.c"); - xml.Attribute("name", "C Sources"); - xml.EndElement(); - - xml.StartElement("group"); - xml.Attribute("pattern", "*.cpp;*.C;*.cxx;*.cc"); - xml.Attribute("name", "C++ Sources"); - xml.EndElement(); - } - - if (enableFortran) { - xml.StartElement("group"); - xml.Attribute("pattern", - "*.f;*.F;*.f77;*.F77;*.f90;*.F90;*.for;*.f95;*.F95"); - xml.Attribute("name", "Fortran Sources"); - xml.EndElement(); - } - - xml.StartElement("group"); - xml.Attribute("pattern", "*.ui"); - xml.Attribute("name", "Qt Designer files"); - xml.EndElement(); - - xml.Element("hidenonprojectfiles", "true"); - xml.EndElement(); // groups - - xml.StartElement("tree"); - xml.Element("hidepatterns", "*.o,*.lo,CVS,*~,cmake*"); - xml.Element("hidenonprojectfiles", "true"); - xml.EndElement(); // tree - - xml.EndElement(); // kdevfileview - xml.EndElement(); // kdevelop; - xml.EndDocument(); - - if (sessionFilename.empty()) { - return; - } - - // and a session file, so that kdevelop opens a file if it opens the - // project the first time - cmGeneratedFileStream devses(sessionFilename.c_str()); - if (!devses) { - return; - } - cmXMLWriter sesxml(devses); - sesxml.StartDocument("UTF-8"); - sesxml.Doctype("KDevPrjSession"); - sesxml.StartElement("KDevPrjSession"); - - sesxml.StartElement("DocsAndViews"); - sesxml.Attribute("NumberOfDocuments", 1); - - sesxml.StartElement("Doc0"); - sesxml.Attribute("NumberOfViews", 1); - sesxml.Attribute("URL", "file://" + fileToOpen); - - sesxml.StartElement("View0"); - sesxml.Attribute("line", 0); - sesxml.Attribute("Type", "Source"); - sesxml.EndElement(); // View0 - - sesxml.EndElement(); // Doc0 - sesxml.EndElement(); // DocsAndViews - sesxml.EndElement(); // KDevPrjSession; -} diff --git a/Source/cmGlobalKdevelopGenerator.h b/Source/cmGlobalKdevelopGenerator.h deleted file mode 100644 index d6c43f3..0000000 --- a/Source/cmGlobalKdevelopGenerator.h +++ /dev/null @@ -1,81 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#ifndef cmGlobalKdevelopGenerator_h -#define cmGlobalKdevelopGenerator_h - -#include "cmConfigure.h" // IWYU pragma: keep - -#include "cmExternalMakefileProjectGenerator.h" - -#include <string> -#include <vector> - -class cmLocalGenerator; - -/** \class cmGlobalKdevelopGenerator - * \brief Write Unix Makefiles accompanied by KDevelop3 project files. - * - * cmGlobalKdevelopGenerator produces a project file for KDevelop 3 (KDevelop - * > 3.1.1). The project is based on the "Custom Makefile based C/C++" - * project of KDevelop. Such a project consists of Unix Makefiles in the - * build directory together with a \<your_project\>.kdevelop project file, - * which contains the project settings and a \<your_project\>.kdevelop.filelist - * file, which lists the source files relative to the kdevelop project - * directory. The kdevelop project directory is the base source directory. - */ -class cmGlobalKdevelopGenerator : public cmExternalMakefileProjectGenerator -{ -public: - cmGlobalKdevelopGenerator(); - - static cmExternalMakefileProjectGeneratorFactory* GetFactory(); - - void Generate() override; - -private: - /*** Create the foo.kdevelop.filelist file, return false if it doesn't - succeed. If the file already exists the contents will be merged. - */ - bool CreateFilelistFile(const std::vector<cmLocalGenerator*>& lgs, - const std::string& outputDir, - const std::string& projectDirIn, - const std::string& projectname, - std::string& cmakeFilePattern, - std::string& fileToOpen); - - /** Create the foo.kdevelop file. This one calls MergeProjectFiles() - if it already exists, otherwise createNewProjectFile() The project - files will be created in \a outputDir (in the build tree), the - kdevelop project dir will be set to \a projectDir (in the source - tree). \a cmakeFilePattern consists of a lists of all cmake - listfiles used by this CMakeLists.txt */ - void CreateProjectFile(const std::string& outputDir, - const std::string& projectDir, - const std::string& projectname, - const std::string& executable, - const std::string& cmakeFilePattern, - const std::string& fileToOpen); - - /*** Reads the old foo.kdevelop line by line and only replaces the - "important" lines - */ - void MergeProjectFiles(const std::string& outputDir, - const std::string& projectDir, - const std::string& filename, - const std::string& executable, - const std::string& cmakeFilePattern, - const std::string& fileToOpen, - const std::string& sessionFilename); - ///! Creates a new foo.kdevelop and a new foo.kdevses file - void CreateNewProjectFile(const std::string& outputDir, - const std::string& projectDir, - const std::string& filename, - const std::string& executable, - const std::string& cmakeFilePattern, - const std::string& fileToOpen, - const std::string& sessionFilename); - - std::vector<std::string> Blacklist; -}; - -#endif diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index d5531cb..b251f86 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -8,7 +8,6 @@ #include "cmsys/FStream.hxx" #include <algorithm> #include <ctype.h> -#include <functional> #include <iterator> #include <memory> // IWYU pragma: keep #include <sstream> @@ -114,7 +113,7 @@ std::string cmGlobalNinjaGenerator::EncodeIdent(const std::string& ident, std::ostream& vars) { if (std::find_if(ident.begin(), ident.end(), - std::not1(std::ptr_fun(IsIdentChar))) != ident.end()) { + [](char c) { return !IsIdentChar(c); }) != ident.end()) { static unsigned VarNum = 0; std::ostringstream names; names << "ident" << VarNum++; @@ -871,7 +870,7 @@ std::string const& cmGlobalNinjaGenerator::ConvertToNinjaPath( cmLocalNinjaGenerator* ng = static_cast<cmLocalNinjaGenerator*>(this->LocalGenerators[0]); - const char* bin_dir = ng->GetState()->GetBinaryDirectory(); + std::string const& bin_dir = ng->GetState()->GetBinaryDirectory(); std::string convPath = ng->ConvertToRelativePath(bin_dir, path); convPath = this->NinjaOutputPath(convPath); #ifdef _WIN32 @@ -903,7 +902,7 @@ void cmGlobalNinjaGenerator::AddCXXCompileCommand( } std::string sourceFileName = sourceFile; - if (!cmSystemTools::FileIsFullPath(sourceFileName.c_str())) { + if (!cmSystemTools::FileIsFullPath(sourceFileName)) { sourceFileName = cmSystemTools::CollapseFullPath( sourceFileName, this->GetCMakeInstance()->GetHomeOutputDirectory()); } @@ -1728,7 +1727,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( info.Requires.push_back(ddi_require.asString()); } } - objects.push_back(info); + objects.push_back(std::move(info)); } // Map from module name to module file path, if known. diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index be40126..d990a6c 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -21,7 +21,6 @@ #include "cmStateDirectory.h" #include "cmStateTypes.h" #include "cmSystemTools.h" -#include "cmTarget.h" #include "cmTargetDepend.h" #include "cmake.h" @@ -421,7 +420,7 @@ void cmGlobalUnixMakefileGenerator3::WriteDirectoryRule2( std::string tname = lg->GetRelativeTargetDirectory(gtarget); tname += "/"; tname += pass; - depends.push_back(tname); + depends.push_back(std::move(tname)); } } } @@ -433,7 +432,7 @@ void cmGlobalUnixMakefileGenerator3::WriteDirectoryRule2( std::string subdir = c.GetDirectory().GetCurrentBinary(); subdir += "/"; subdir += pass; - depends.push_back(subdir); + depends.push_back(std::move(subdir)); } // Work-around for makes that drop rules that have no dependencies @@ -460,10 +459,9 @@ void cmGlobalUnixMakefileGenerator3::WriteDirectoryRules2( } // Begin the directory-level rules section. - std::string dir = cmSystemTools::ConvertToOutputPath( - lg->ConvertToRelativePath(lg->GetBinaryDirectory(), - lg->GetCurrentBinaryDirectory()) - .c_str()); + std::string dir = + cmSystemTools::ConvertToOutputPath(lg->ConvertToRelativePath( + lg->GetBinaryDirectory(), lg->GetCurrentBinaryDirectory())); lg->WriteDivider(ruleFileStream); ruleFileStream << "# Directory level rules for directory " << dir << "\n\n"; @@ -514,7 +512,7 @@ void cmGlobalUnixMakefileGenerator3::GenerateBuildCommand( tname = conv.ConvertToRelativePath(mf->GetState()->GetBinaryDirectory(), tname); cmSystemTools::ConvertToOutputSlashes(tname); - makeCommand.push_back(tname); + makeCommand.push_back(std::move(tname)); if (this->Makefiles.empty()) { delete mf; } @@ -630,8 +628,6 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( makefileName = localName; makefileName += "/build.make"; - bool needRequiresStep = this->NeedRequiresStep(gtarget); - lg->WriteDivider(ruleFileStream); ruleFileStream << "# Target rules for target " << localName << "\n\n"; @@ -641,13 +637,6 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( commands.push_back( lg->GetRecursiveMakeCall(makefileName.c_str(), makeTargetName)); - // add requires if we need it for this generator - if (needRequiresStep) { - makeTargetName = localName; - makeTargetName += "/requires"; - commands.push_back( - lg->GetRecursiveMakeCall(makefileName.c_str(), makeTargetName)); - } makeTargetName = localName; makeTargetName += "/build"; commands.push_back( @@ -952,21 +941,3 @@ void cmGlobalUnixMakefileGenerator3::WriteHelpRule( commands, true); ruleFileStream << "\n\n"; } - -bool cmGlobalUnixMakefileGenerator3::NeedRequiresStep( - const cmGeneratorTarget* target) -{ - std::set<std::string> languages; - target->GetLanguages( - languages, - target->Target->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE")); - for (std::string const& l : languages) { - std::string var = "CMAKE_NEEDS_REQUIRES_STEP_"; - var += l; - var += "_FLAG"; - if (target->Target->GetMakefile()->GetDefinition(var)) { - return true; - } - } - return false; -} diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h index d601f88..f9ce88c 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.h +++ b/Source/cmGlobalUnixMakefileGenerator3.h @@ -174,9 +174,6 @@ protected: void AppendGlobalTargetDepends(std::vector<std::string>& depends, cmGeneratorTarget* target); - // does this generator need a requires step for any of its targets - bool NeedRequiresStep(cmGeneratorTarget const*); - // Target name hooks for superclass. const char* GetAllTargetName() const override { return "all"; } const char* GetInstallTargetName() const override { return "install"; } diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index 8c9e461..73a5dae 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -478,12 +478,11 @@ void cmGlobalVisualStudio10Generator::Generate() void cmGlobalVisualStudio10Generator::EnableLanguage( std::vector<std::string> const& lang, cmMakefile* mf, bool optional) { - for (std::vector<std::string>::const_iterator it = lang.begin(); - it != lang.end(); ++it) { - if (*it == "ASM_NASM") { + for (std::string const& it : lang) { + if (it == "ASM_NASM") { this->NasmEnabled = true; } - if (*it == "CUDA") { + if (it == "CUDA") { this->CudaEnabled = true; } } @@ -829,8 +828,9 @@ void cmGlobalVisualStudio10Generator::GenerateBuildCommand( if (parser.ParseFile(slnFile, slnData, cmVisualStudioSlnParser::DataGroupProjects)) { std::vector<cmSlnProjectEntry> slnProjects = slnData.GetProjects(); - for (std::vector<cmSlnProjectEntry>::iterator i = slnProjects.begin(); - !useDevEnv && i != slnProjects.end(); ++i) { + for (std::vector<cmSlnProjectEntry>::const_iterator i = + slnProjects.cbegin(); + !useDevEnv && i != slnProjects.cend(); ++i) { std::string proj = i->GetRelativePath(); if (proj.size() > 7 && proj.substr(proj.size() - 7) == ".vfproj") { useDevEnv = true; @@ -951,6 +951,11 @@ void cmGlobalVisualStudio10Generator::PathTooLong(cmGeneratorTarget* target, } } +std::string cmGlobalVisualStudio10Generator::Encoding() +{ + return "utf-8"; +} + bool cmGlobalVisualStudio10Generator::IsNsightTegra() const { return !this->NsightTegraVersion.empty(); diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h index 5f80c73..f2501c2 100644 --- a/Source/cmGlobalVisualStudio10Generator.h +++ b/Source/cmGlobalVisualStudio10Generator.h @@ -18,29 +18,31 @@ public: const std::string& platformName); static cmGlobalGeneratorFactory* NewFactory(); - virtual bool MatchesGeneratorName(const std::string& name) const; + bool MatchesGeneratorName(const std::string& name) const override; - virtual bool SetSystemName(std::string const& s, cmMakefile* mf); - virtual bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf); - virtual bool SetGeneratorToolset(std::string const& ts, cmMakefile* mf); + bool SetSystemName(std::string const& s, cmMakefile* mf) override; + bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf) override; + bool SetGeneratorToolset(std::string const& ts, cmMakefile* mf) override; - virtual void GenerateBuildCommand( - std::vector<std::string>& makeCommand, const std::string& makeProgram, - const std::string& projectName, const std::string& projectDir, - const std::string& targetName, const std::string& config, bool fast, - bool verbose, - std::vector<std::string> const& makeOptions = std::vector<std::string>()); + void GenerateBuildCommand(std::vector<std::string>& makeCommand, + const std::string& makeProgram, + const std::string& projectName, + const std::string& projectDir, + const std::string& targetName, + const std::string& config, bool fast, bool verbose, + std::vector<std::string> const& makeOptions = + std::vector<std::string>()) override; ///! create the correct local generator - virtual cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf); + cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override; /** * Try to determine system information such as shared library * extension, pthreads, byte order etc. */ - virtual void EnableLanguage(std::vector<std::string> const& languages, - cmMakefile*, bool optional); - virtual void WriteSLNHeader(std::ostream& fout); + void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*, + bool optional) override; + void WriteSLNHeader(std::ostream& fout) override; bool IsCudaEnabled() const { return this->CudaEnabled; } @@ -87,15 +89,16 @@ public: /** Return true if building for WindowsStore */ bool TargetsWindowsStore() const { return this->SystemIsWindowsStore; } - virtual const char* GetCMakeCFGIntDir() const { return "$(Configuration)"; } + const char* GetCMakeCFGIntDir() const override { return "$(Configuration)"; } bool Find64BitTools(cmMakefile* mf); /** Generate an <output>.rule file path for a given command output. */ - virtual std::string GenerateRuleFile(std::string const& output) const; + std::string GenerateRuleFile(std::string const& output) const override; void PathTooLong(cmGeneratorTarget* target, cmSourceFile const* sf, std::string const& sfRel); + std::string Encoding() override; virtual const char* GetToolsVersion() { return "4.0"; } bool FindMakeProgram(cmMakefile* mf) override; @@ -113,7 +116,7 @@ public: cmIDEFlagTable const* GetNasmFlagTable() const; protected: - virtual void Generate(); + void Generate() override; virtual bool InitializeSystem(cmMakefile* mf); virtual bool InitializeWindows(cmMakefile* mf); virtual bool InitializeWindowsCE(cmMakefile* mf); @@ -127,7 +130,7 @@ protected: virtual bool SelectWindowsPhoneToolset(std::string& toolset) const; virtual bool SelectWindowsStoreToolset(std::string& toolset) const; - virtual const char* GetIDEVersion() { return "10.0"; } + const char* GetIDEVersion() override { return "10.0"; } std::string const& GetMSBuildCommand(); @@ -173,8 +176,8 @@ private: bool MSBuildCommandInitialized; cmVisualStudio10ToolsetOptions ToolsetOptions; virtual std::string FindMSBuildCommand(); - virtual std::string FindDevEnvCommand(); - virtual std::string GetVSMakeProgram() { return this->GetMSBuildCommand(); } + std::string FindDevEnvCommand() override; + std::string GetVSMakeProgram() override { return this->GetMSBuildCommand(); } bool PlatformToolsetNeedsDebugEnum; @@ -186,6 +189,6 @@ private: bool CudaEnabled; // We do not use the reload macros for VS >= 10. - virtual std::string GetUserMacrosDirectory() { return ""; } + std::string GetUserMacrosDirectory() override { return ""; } }; #endif diff --git a/Source/cmGlobalVisualStudio11Generator.cxx b/Source/cmGlobalVisualStudio11Generator.cxx index cb3b047..f1d5a8c 100644 --- a/Source/cmGlobalVisualStudio11Generator.cxx +++ b/Source/cmGlobalVisualStudio11Generator.cxx @@ -83,9 +83,8 @@ public: std::set<std::string> installedSDKs = cmGlobalVisualStudio11Generator::GetInstalledWindowsCESDKs(); - for (std::set<std::string>::const_iterator i = installedSDKs.begin(); - i != installedSDKs.end(); ++i) { - names.push_back(std::string(vs11generatorName) + " " + *i); + for (std::string const& i : installedSDKs) { + names.push_back(std::string(vs11generatorName) + " " + i); } } @@ -224,18 +223,17 @@ cmGlobalVisualStudio11Generator::GetInstalledWindowsCESDKs() cmSystemTools::KeyWOW64_32); std::set<std::string> ret; - for (std::vector<std::string>::const_iterator i = subkeys.begin(); - i != subkeys.end(); ++i) { + for (std::string const& i : subkeys) { std::string key = sdksKey; key += '\\'; - key += *i; + key += i; key += ';'; std::string path; - if (cmSystemTools::ReadRegistryValue(key.c_str(), path, + if (cmSystemTools::ReadRegistryValue(key, path, cmSystemTools::KeyWOW64_32) && !path.empty()) { - ret.insert(*i); + ret.insert(i); } } diff --git a/Source/cmGlobalVisualStudio11Generator.h b/Source/cmGlobalVisualStudio11Generator.h index 8b75aad..40f02fb 100644 --- a/Source/cmGlobalVisualStudio11Generator.h +++ b/Source/cmGlobalVisualStudio11Generator.h @@ -24,15 +24,15 @@ public: const std::string& platformName); static cmGlobalGeneratorFactory* NewFactory(); - virtual bool MatchesGeneratorName(const std::string& name) const; + bool MatchesGeneratorName(const std::string& name) const override; - virtual void WriteSLNHeader(std::ostream& fout); + void WriteSLNHeader(std::ostream& fout) override; protected: - virtual bool InitializeWindowsPhone(cmMakefile* mf); - virtual bool InitializeWindowsStore(cmMakefile* mf); - virtual bool SelectWindowsPhoneToolset(std::string& toolset) const; - virtual bool SelectWindowsStoreToolset(std::string& toolset) const; + bool InitializeWindowsPhone(cmMakefile* mf) override; + bool InitializeWindowsStore(cmMakefile* mf) override; + bool SelectWindowsPhoneToolset(std::string& toolset) const override; + bool SelectWindowsStoreToolset(std::string& toolset) const override; // Used to verify that the Desktop toolset for the current generator is // installed on the machine. @@ -43,12 +43,12 @@ protected: bool IsWindowsPhoneToolsetInstalled() const; bool IsWindowsStoreToolsetInstalled() const; - virtual const char* GetIDEVersion() { return "11.0"; } + const char* GetIDEVersion() override { return "11.0"; } bool UseFolderProperty(); static std::set<std::string> GetInstalledWindowsCESDKs(); /** Return true if the configuration needs to be deployed */ - virtual bool NeedsDeploy(cmStateEnums::TargetType type) const; + bool NeedsDeploy(cmStateEnums::TargetType type) const override; private: class Factory; diff --git a/Source/cmGlobalVisualStudio12Generator.h b/Source/cmGlobalVisualStudio12Generator.h index 5ba21a6..c941809 100644 --- a/Source/cmGlobalVisualStudio12Generator.h +++ b/Source/cmGlobalVisualStudio12Generator.h @@ -22,32 +22,32 @@ public: const std::string& platformName); static cmGlobalGeneratorFactory* NewFactory(); - virtual bool MatchesGeneratorName(const std::string& name) const; + bool MatchesGeneratorName(const std::string& name) const override; - virtual void WriteSLNHeader(std::ostream& fout); + void WriteSLNHeader(std::ostream& fout) override; // in Visual Studio 2013 they detached the MSBuild tools version // from the .Net Framework version and instead made it have it's own // version number - virtual const char* GetToolsVersion() { return "12.0"; } + const char* GetToolsVersion() override { return "12.0"; } protected: bool ProcessGeneratorToolsetField(std::string const& key, std::string const& value) override; - virtual bool InitializeWindowsPhone(cmMakefile* mf); - virtual bool InitializeWindowsStore(cmMakefile* mf); - virtual bool SelectWindowsPhoneToolset(std::string& toolset) const; - virtual bool SelectWindowsStoreToolset(std::string& toolset) const; + bool InitializeWindowsPhone(cmMakefile* mf) override; + bool InitializeWindowsStore(cmMakefile* mf) override; + bool SelectWindowsPhoneToolset(std::string& toolset) const override; + bool SelectWindowsStoreToolset(std::string& toolset) const override; // Used to verify that the Desktop toolset for the current generator is // installed on the machine. - virtual bool IsWindowsDesktopToolsetInstalled() const; + bool IsWindowsDesktopToolsetInstalled() const override; // These aren't virtual because we need to check if the selected version // of the toolset is installed bool IsWindowsPhoneToolsetInstalled() const; bool IsWindowsStoreToolsetInstalled() const; - virtual const char* GetIDEVersion() { return "12.0"; } + const char* GetIDEVersion() override { return "12.0"; } private: class Factory; }; diff --git a/Source/cmGlobalVisualStudio14Generator.cxx b/Source/cmGlobalVisualStudio14Generator.cxx index 97d5313..c440e0d 100644 --- a/Source/cmGlobalVisualStudio14Generator.cxx +++ b/Source/cmGlobalVisualStudio14Generator.cxx @@ -257,9 +257,8 @@ std::string cmGlobalVisualStudio14Generator::GetWindows10SDKVersion() std::vector<std::string> sdks; // Grab the paths of the different SDKs that are installed - for (std::vector<std::string>::iterator i = win10Roots.begin(); - i != win10Roots.end(); ++i) { - std::string path = *i + "/Include/*"; + for (std::string const& i : win10Roots) { + std::string path = i + "/Include/*"; cmSystemTools::GlobDirs(path, sdks); } @@ -269,19 +268,17 @@ std::string cmGlobalVisualStudio14Generator::GetWindows10SDKVersion() if (!sdks.empty()) { // Only use the filename, which will be the SDK version. - for (std::vector<std::string>::iterator i = sdks.begin(); i != sdks.end(); - ++i) { - *i = cmSystemTools::GetFilenameName(*i); + for (std::string& i : sdks) { + i = cmSystemTools::GetFilenameName(i); } // Sort the results to make sure we select the most recent one. std::sort(sdks.begin(), sdks.end(), cmSystemTools::VersionCompareGreater); // Look for a SDK exactly matching the requested target version. - for (std::vector<std::string>::iterator i = sdks.begin(); i != sdks.end(); - ++i) { - if (cmSystemTools::VersionCompareEqual(*i, this->SystemVersion)) { - return *i; + for (std::string const& i : sdks) { + if (cmSystemTools::VersionCompareEqual(i, this->SystemVersion)) { + return i; } } diff --git a/Source/cmGlobalVisualStudio14Generator.h b/Source/cmGlobalVisualStudio14Generator.h index 425fb22..d92a11a 100644 --- a/Source/cmGlobalVisualStudio14Generator.h +++ b/Source/cmGlobalVisualStudio14Generator.h @@ -22,26 +22,26 @@ public: const std::string& platformName); static cmGlobalGeneratorFactory* NewFactory(); - virtual bool MatchesGeneratorName(const std::string& name) const; + bool MatchesGeneratorName(const std::string& name) const override; - virtual void WriteSLNHeader(std::ostream& fout); + void WriteSLNHeader(std::ostream& fout) override; - virtual const char* GetToolsVersion() { return "14.0"; } + const char* GetToolsVersion() override { return "14.0"; } protected: - virtual bool InitializeWindows(cmMakefile* mf); - virtual bool InitializeWindowsStore(cmMakefile* mf); - virtual bool SelectWindowsStoreToolset(std::string& toolset) const; + bool InitializeWindows(cmMakefile* mf) override; + bool InitializeWindowsStore(cmMakefile* mf) override; + bool SelectWindowsStoreToolset(std::string& toolset) const override; // These aren't virtual because we need to check if the selected version // of the toolset is installed bool IsWindowsStoreToolsetInstalled() const; - virtual const char* GetIDEVersion() { return "14.0"; } + const char* GetIDEVersion() override { return "14.0"; } virtual bool SelectWindows10SDK(cmMakefile* mf, bool required); // Used to verify that the Desktop toolset for the current generator is // installed on the machine. - virtual bool IsWindowsDesktopToolsetInstalled() const; + bool IsWindowsDesktopToolsetInstalled() const override; std::string GetWindows10SDKVersion(); 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..4f4e0b9 100644 --- a/Source/cmGlobalVisualStudio15Generator.h +++ b/Source/cmGlobalVisualStudio15Generator.h @@ -22,20 +22,25 @@ public: const std::string& platformName); static cmGlobalGeneratorFactory* NewFactory(); - virtual bool MatchesGeneratorName(const std::string& name) const; + bool MatchesGeneratorName(const std::string& name) const override; - virtual void WriteSLNHeader(std::ostream& fout); + void WriteSLNHeader(std::ostream& fout) override; + + const char* GetToolsVersion() override { return "15.0"; } + + bool SetGeneratorInstance(std::string const& i, cmMakefile* mf) override; + + bool GetVSInstance(std::string& dir) const; - virtual const char* GetToolsVersion() { return "15.0"; } protected: bool InitializeWindows(cmMakefile* mf) override; - virtual bool SelectWindowsStoreToolset(std::string& toolset) const; + bool SelectWindowsStoreToolset(std::string& toolset) const override; - virtual const char* GetIDEVersion() { return "15.0"; } + const char* GetIDEVersion() override { return "15.0"; } // Used to verify that the Desktop toolset for the current generator is // installed on the machine. - virtual bool IsWindowsDesktopToolsetInstalled() const; + bool IsWindowsDesktopToolsetInstalled() const override; // These aren't virtual because we need to check if the selected version // of the toolset is installed diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx index 3b45c90..45cc583 100644 --- a/Source/cmGlobalVisualStudio71Generator.cxx +++ b/Source/cmGlobalVisualStudio71Generator.cxx @@ -76,9 +76,8 @@ void cmGlobalVisualStudio71Generator::WriteSolutionConfigurations( std::ostream& fout, std::vector<std::string> const& configs) { fout << "\tGlobalSection(SolutionConfiguration) = preSolution\n"; - for (std::vector<std::string>::const_iterator i = configs.begin(); - i != configs.end(); ++i) { - fout << "\t\t" << *i << " = " << *i << "\n"; + for (std::string const& i : configs) { + fout << "\t\t" << i << " = " << i << "\n"; } fout << "\tEndGlobalSection\n"; } @@ -143,9 +142,7 @@ void cmGlobalVisualStudio71Generator::WriteProjectDepends( cmGeneratorTarget const* target) { VSDependSet const& depends = this->VSTargetDepends[target]; - for (VSDependSet::const_iterator di = depends.begin(); di != depends.end(); - ++di) { - const char* name = di->c_str(); + for (std::string const& name : depends) { std::string guid = this->GetGUID(name); if (guid.empty()) { std::string m = "Target: "; @@ -174,11 +171,10 @@ void cmGlobalVisualStudio71Generator::WriteExternalProject( // project instead of in the global section if (!depends.empty()) { fout << "\tProjectSection(ProjectDependencies) = postProject\n"; - std::set<std::string>::const_iterator it; - for (it = depends.begin(); it != depends.end(); ++it) { - if (!it->empty()) { - fout << "\t\t{" << this->GetGUID(it->c_str()) << "} = {" - << this->GetGUID(it->c_str()) << "}\n"; + for (std::string const& it : depends) { + if (!it.empty()) { + fout << "\t\t{" << this->GetGUID(it) << "} = {" << this->GetGUID(it) + << "}\n"; } } fout << "\tEndProjectSection\n"; @@ -198,31 +194,30 @@ void cmGlobalVisualStudio71Generator::WriteProjectConfigurations( const std::string& platformName = !platformMapping.empty() ? platformMapping : this->GetPlatformName(); std::string guid = this->GetGUID(name); - for (std::vector<std::string>::const_iterator i = configs.begin(); - i != configs.end(); ++i) { + for (std::string const& i : configs) { std::vector<std::string> mapConfig; - const char* dstConfig = i->c_str(); + const char* dstConfig = i.c_str(); if (target.GetProperty("EXTERNAL_MSPROJECT")) { if (const char* m = target.GetProperty("MAP_IMPORTED_CONFIG_" + - cmSystemTools::UpperCase(*i))) { + cmSystemTools::UpperCase(i))) { cmSystemTools::ExpandListArgument(m, mapConfig); if (!mapConfig.empty()) { dstConfig = mapConfig[0].c_str(); } } } - fout << "\t\t{" << guid << "}." << *i << ".ActiveCfg = " << dstConfig - << "|" << platformName << std::endl; + fout << "\t\t{" << guid << "}." << i << ".ActiveCfg = " << dstConfig << "|" + << platformName << std::endl; std::set<std::string>::const_iterator ci = - configsPartOfDefaultBuild.find(*i); + configsPartOfDefaultBuild.find(i); if (!(ci == configsPartOfDefaultBuild.end())) { - fout << "\t\t{" << guid << "}." << *i << ".Build.0 = " << dstConfig - << "|" << platformName << std::endl; + fout << "\t\t{" << guid << "}." << i << ".Build.0 = " << dstConfig << "|" + << platformName << std::endl; } } } -// 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/cmGlobalVisualStudio71Generator.h b/Source/cmGlobalVisualStudio71Generator.h index 0ce02aa..054c342 100644 --- a/Source/cmGlobalVisualStudio71Generator.h +++ b/Source/cmGlobalVisualStudio71Generator.h @@ -17,25 +17,24 @@ public: const std::string& platformName = ""); protected: - virtual void WriteSLNFile(std::ostream& fout, cmLocalGenerator* root, - std::vector<cmLocalGenerator*>& generators); + void WriteSLNFile(std::ostream& fout, cmLocalGenerator* root, + std::vector<cmLocalGenerator*>& generators) override; virtual void WriteSolutionConfigurations( std::ostream& fout, std::vector<std::string> const& configs); - virtual void WriteProject(std::ostream& fout, const std::string& name, - const char* path, const cmGeneratorTarget* t); - virtual void WriteProjectDepends(std::ostream& fout, const std::string& name, - const char* path, - cmGeneratorTarget const* t); - virtual void WriteProjectConfigurations( + void WriteProject(std::ostream& fout, const std::string& name, + const char* path, const cmGeneratorTarget* t) override; + void WriteProjectDepends(std::ostream& fout, const std::string& name, + const char* path, + cmGeneratorTarget const* t) override; + void WriteProjectConfigurations( std::ostream& fout, const std::string& name, cmGeneratorTarget const& target, std::vector<std::string> const& configs, const std::set<std::string>& configsPartOfDefaultBuild, - const std::string& platformMapping = ""); - virtual void WriteExternalProject(std::ostream& fout, - const std::string& name, const char* path, - const char* typeGuid, - const std::set<std::string>& depends); - virtual void WriteSLNHeader(std::ostream& fout); + const std::string& platformMapping = "") override; + void WriteExternalProject(std::ostream& fout, const std::string& name, + const char* path, const char* typeGuid, + const std::set<std::string>& depends) override; + void WriteSLNHeader(std::ostream& fout) override; // Folders are not supported by VS 7.1. virtual bool UseFolderProperty() { return false; } diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index a14b5f7..c915dc5 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -334,9 +334,8 @@ void cmGlobalVisualStudio7Generator::OutputSLNFile( // output the SLN file void cmGlobalVisualStudio7Generator::OutputSLNFile() { - std::map<std::string, std::vector<cmLocalGenerator*>>::iterator it; - for (it = this->ProjectMap.begin(); it != this->ProjectMap.end(); ++it) { - this->OutputSLNFile(it->second[0], it->second); + for (auto& it : this->ProjectMap) { + this->OutputSLNFile(it.second[0], it.second); } } @@ -346,9 +345,7 @@ void cmGlobalVisualStudio7Generator::WriteTargetConfigurations( { // loop over again and write out configurations for each target // in the solution - for (OrderedTargetDependSet::const_iterator tt = projectTargets.begin(); - tt != projectTargets.end(); ++tt) { - cmGeneratorTarget const* target = *tt; + for (cmGeneratorTarget const* target : projectTargets) { if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } @@ -378,9 +375,7 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution( VisualStudioFolders.clear(); std::string rootBinaryDir = root->GetCurrentBinaryDirectory(); - for (OrderedTargetDependSet::const_iterator tt = projectTargets.begin(); - tt != projectTargets.end(); ++tt) { - cmGeneratorTarget const* target = *tt; + for (cmGeneratorTarget const* target : projectTargets) { if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } @@ -420,19 +415,18 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution( std::string cumulativePath; - for (std::vector<cmsys::String>::iterator iter = tokens.begin(); - iter != tokens.end(); ++iter) { - if (!iter->size()) { + for (cmsys::String const& iter : tokens) { + if (!iter.size()) { continue; } if (cumulativePath.empty()) { - cumulativePath = "CMAKE_FOLDER_GUID_" + *iter; + cumulativePath = "CMAKE_FOLDER_GUID_" + iter; } else { VisualStudioFolders[cumulativePath].insert(cumulativePath + "/" + - *iter); + iter); - cumulativePath = cumulativePath + "/" + *iter; + cumulativePath = cumulativePath + "/" + iter; } } @@ -447,9 +441,7 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution( void cmGlobalVisualStudio7Generator::WriteTargetDepends( std::ostream& fout, OrderedTargetDependSet const& projectTargets) { - for (OrderedTargetDependSet::const_iterator tt = projectTargets.begin(); - tt != projectTargets.end(); ++tt) { - cmGeneratorTarget const* target = *tt; + for (cmGeneratorTarget const* target : projectTargets) { if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } @@ -467,11 +459,9 @@ void cmGlobalVisualStudio7Generator::WriteFolders(std::ostream& fout) const char* prefix = "CMAKE_FOLDER_GUID_"; const std::string::size_type skip_prefix = strlen(prefix); std::string guidProjectTypeFolder = "2150E333-8FDC-42A3-9474-1A3956D46DE8"; - for (std::map<std::string, std::set<std::string>>::iterator iter = - VisualStudioFolders.begin(); - iter != VisualStudioFolders.end(); ++iter) { - std::string fullName = iter->first; - std::string guid = this->GetGUID(fullName.c_str()); + for (auto const& iter : VisualStudioFolders) { + std::string fullName = iter.first; + std::string guid = this->GetGUID(fullName); std::replace(fullName.begin(), fullName.end(), '/', '\\'); if (cmSystemTools::StringStartsWith(fullName.c_str(), prefix)) { @@ -487,16 +477,13 @@ void cmGlobalVisualStudio7Generator::WriteFolders(std::ostream& fout) void cmGlobalVisualStudio7Generator::WriteFoldersContent(std::ostream& fout) { - for (std::map<std::string, std::set<std::string>>::iterator iter = - VisualStudioFolders.begin(); - iter != VisualStudioFolders.end(); ++iter) { - std::string key(iter->first); - std::string guidParent(this->GetGUID(key.c_str())); + for (auto const& iter : VisualStudioFolders) { + std::string key(iter.first); + std::string guidParent(this->GetGUID(key)); - for (std::set<std::string>::iterator it = iter->second.begin(); - it != iter->second.end(); ++it) { - std::string value(*it); - std::string guid(this->GetGUID(value.c_str())); + for (std::string const& it : iter.second) { + std::string value(it); + std::string guid(this->GetGUID(value)); fout << "\t\t{" << guid << "} = {" << guidParent << "}\n"; } @@ -525,11 +512,10 @@ void cmGlobalVisualStudio7Generator::WriteSLNGlobalSections( bool extensibilityAddInsOverridden = false; const std::vector<std::string> propKeys = root->GetMakefile()->GetPropertyKeys(); - for (std::vector<std::string>::const_iterator it = propKeys.begin(); - it != propKeys.end(); ++it) { - if (it->find("VS_GLOBAL_SECTION_") == 0) { + for (std::string const& it : propKeys) { + if (it.find("VS_GLOBAL_SECTION_") == 0) { std::string sectionType; - std::string name = it->substr(18); + std::string name = it.substr(18); if (name.find("PRE_") == 0) { name = name.substr(4); sectionType = "preSolution"; @@ -549,17 +535,15 @@ void cmGlobalVisualStudio7Generator::WriteSLNGlobalSections( } fout << "\tGlobalSection(" << name << ") = " << sectionType << "\n"; std::vector<std::string> keyValuePairs; - cmSystemTools::ExpandListArgument( - root->GetMakefile()->GetProperty(it->c_str()), keyValuePairs); - for (std::vector<std::string>::const_iterator itPair = - keyValuePairs.begin(); - itPair != keyValuePairs.end(); ++itPair) { - const std::string::size_type posEqual = itPair->find('='); + cmSystemTools::ExpandListArgument(root->GetMakefile()->GetProperty(it), + keyValuePairs); + for (std::string const& itPair : keyValuePairs) { + const std::string::size_type posEqual = itPair.find('='); if (posEqual != std::string::npos) { const std::string key = - cmSystemTools::TrimWhitespace(itPair->substr(0, posEqual)); + cmSystemTools::TrimWhitespace(itPair.substr(0, posEqual)); const std::string value = - cmSystemTools::TrimWhitespace(itPair->substr(posEqual + 1)); + cmSystemTools::TrimWhitespace(itPair.substr(posEqual + 1)); fout << "\t\t" << key << " = " << value << "\n"; if (key == "SolutionGuid") { addGuid = false; @@ -618,14 +602,13 @@ std::string cmGlobalVisualStudio7Generator::WriteUtilityDepend( "\t<Configurations>\n" ; /* clang-format on */ - for (std::vector<std::string>::iterator i = configs.begin(); - i != configs.end(); ++i) { + for (std::string const& i : configs) { /* clang-format off */ fout << "\t\t<Configuration\n" - "\t\t\tName=\"" << *i << "|Win32\"\n" - "\t\t\tOutputDirectory=\"" << *i << "\"\n" - "\t\t\tIntermediateDirectory=\"" << pname << ".dir\\" << *i << "\"\n" + "\t\t\tName=\"" << i << "|Win32\"\n" + "\t\t\tOutputDirectory=\"" << i << "\"\n" + "\t\t\tIntermediateDirectory=\"" << pname << ".dir\\" << i << "\"\n" "\t\t\tConfigurationType=\"10\"\n" "\t\t\tUseOfMFC=\"0\"\n" "\t\t\tATLMinimizesCRunTimeLibraryUsage=\"FALSE\"\n" @@ -696,23 +679,21 @@ std::set<std::string> cmGlobalVisualStudio7Generator::IsPartOfDefaultBuild( std::vector<std::string> targetNames; targetNames.push_back("INSTALL"); targetNames.push_back("PACKAGE"); - for (std::vector<std::string>::const_iterator t = targetNames.begin(); - t != targetNames.end(); ++t) { - // check if target <*t> is part of default build - if (target->GetName() == *t) { + for (std::string const& t : targetNames) { + // check if target <t> is part of default build + if (target->GetName() == t) { const std::string propertyName = - "CMAKE_VS_INCLUDE_" + *t + "_TO_DEFAULT_BUILD"; - // inspect CMAKE_VS_INCLUDE_<*t>_TO_DEFAULT_BUILD properties - for (std::vector<std::string>::const_iterator i = configs.begin(); - i != configs.end(); ++i) { + "CMAKE_VS_INCLUDE_" + t + "_TO_DEFAULT_BUILD"; + // inspect CMAKE_VS_INCLUDE_<t>_TO_DEFAULT_BUILD properties + for (std::string const& i : configs) { const char* propertyValue = target->Target->GetMakefile()->GetDefinition(propertyName); cmGeneratorExpression ge; std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(propertyValue); if (cmSystemTools::IsOn( - cge->Evaluate(target->GetLocalGenerator(), *i))) { - activeConfigs.insert(*i); + cge->Evaluate(target->GetLocalGenerator(), i))) { + activeConfigs.insert(i); } } } @@ -724,12 +705,11 @@ std::set<std::string> cmGlobalVisualStudio7Generator::IsPartOfDefaultBuild( return activeConfigs; } // inspect EXCLUDE_FROM_DEFAULT_BUILD[_<CONFIG>] properties - for (std::vector<std::string>::const_iterator i = configs.begin(); - i != configs.end(); ++i) { + for (std::string const& i : configs) { const char* propertyValue = - target->GetFeature("EXCLUDE_FROM_DEFAULT_BUILD", i->c_str()); + target->GetFeature("EXCLUDE_FROM_DEFAULT_BUILD", i); if (cmSystemTools::IsOff(propertyValue)) { - activeConfigs.insert(*i); + activeConfigs.insert(i); } } return activeConfigs; @@ -738,9 +718,8 @@ std::set<std::string> cmGlobalVisualStudio7Generator::IsPartOfDefaultBuild( bool cmGlobalVisualStudio7Generator::IsDependedOn( OrderedTargetDependSet const& projectTargets, cmGeneratorTarget const* gtIn) { - for (OrderedTargetDependSet::const_iterator l = projectTargets.begin(); - l != projectTargets.end(); ++l) { - TargetDependSet const& tgtdeps = this->GetTargetDirectDepends(*l); + for (cmTargetDepend const& l : projectTargets) { + TargetDependSet const& tgtdeps = this->GetTargetDirectDepends(l); if (tgtdeps.count(gtIn)) { return true; } diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h index c5aced4..8d1bdc0 100644 --- a/Source/cmGlobalVisualStudio7Generator.h +++ b/Source/cmGlobalVisualStudio7Generator.h @@ -26,11 +26,11 @@ public: std::string const& GetPlatformName() const; ///! Create a local generator appropriate to this Global Generator - virtual cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf); + cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override; - virtual bool SetSystemName(std::string const& s, cmMakefile* mf); + bool SetSystemName(std::string const& s, cmMakefile* mf) override; - virtual bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf); + bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf) override; /** * Utilized by the generator factory to determine if this generator @@ -48,19 +48,21 @@ public: * Try to determine system information such as shared library * extension, pthreads, byte order etc. */ - virtual void EnableLanguage(std::vector<std::string> const& languages, - cmMakefile*, bool optional); + void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*, + bool optional) override; /** * Try running cmake and building a file. This is used for dynamically * loaded commands, not as part of the usual build process. */ - virtual void GenerateBuildCommand( - std::vector<std::string>& makeCommand, const std::string& makeProgram, - const std::string& projectName, const std::string& projectDir, - const std::string& targetName, const std::string& config, bool fast, - bool verbose, - std::vector<std::string> const& makeOptions = std::vector<std::string>()); + void GenerateBuildCommand(std::vector<std::string>& makeCommand, + const std::string& makeProgram, + const std::string& projectName, + const std::string& projectDir, + const std::string& targetName, + const std::string& config, bool fast, bool verbose, + std::vector<std::string> const& makeOptions = + std::vector<std::string>()) override; /** * Generate the DSW workspace file. @@ -71,13 +73,13 @@ public: std::string GetGUID(std::string const& name); /** Append the subdirectory for the given configuration. */ - virtual void AppendDirectoryForConfig(const std::string& prefix, - const std::string& config, - const std::string& suffix, - std::string& dir); + void AppendDirectoryForConfig(const std::string& prefix, + const std::string& config, + const std::string& suffix, + std::string& dir) override; ///! What is the configurations directory variable called? - virtual const char* GetCMakeCFGIntDir() const + const char* GetCMakeCFGIntDir() const override { return "$(ConfigurationName)"; } @@ -103,7 +105,7 @@ public: cmIDEFlagTable const* ExtraFlagTable; protected: - virtual void Generate(); + void Generate() override; virtual const char* GetIDEVersion() = 0; std::string const& GetDevEnvCommand(); @@ -129,7 +131,7 @@ protected: cmLocalGenerator* root); virtual void WriteSLNFooter(std::ostream& fout); virtual void WriteSLNHeader(std::ostream& fout) = 0; - virtual std::string WriteUtilityDepend(const cmGeneratorTarget* target); + std::string WriteUtilityDepend(const cmGeneratorTarget* target) override; virtual void WriteTargetsToSolution( std::ostream& fout, cmLocalGenerator* root, @@ -170,7 +172,7 @@ private: char* IntelProjectVersion; std::string DevEnvCommand; bool DevEnvCommandInitialized; - virtual std::string GetVSMakeProgram() { return this->GetDevEnvCommand(); } + std::string GetVSMakeProgram() override { return this->GetDevEnvCommand(); } }; #define CMAKE_CHECK_BUILD_SYSTEM_TARGET "ZERO_CHECK" diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx index cc1d1a2..ab8ad70 100644 --- a/Source/cmGlobalVisualStudio8Generator.cxx +++ b/Source/cmGlobalVisualStudio8Generator.cxx @@ -66,10 +66,8 @@ public: parser.ParseVersion("8.0"); const std::vector<std::string>& availablePlatforms = parser.GetAvailablePlatforms(); - for (std::vector<std::string>::const_iterator i = - availablePlatforms.begin(); - i != availablePlatforms.end(); ++i) { - names.push_back("Visual Studio 8 2005 " + *i); + for (std::string const& i : availablePlatforms) { + names.push_back("Visual Studio 8 2005 " + i); } } @@ -117,9 +115,8 @@ std::string cmGlobalVisualStudio8Generator::FindDevEnvCommand() void cmGlobalVisualStudio8Generator::EnableLanguage( std::vector<std::string> const& lang, cmMakefile* mf, bool optional) { - for (std::vector<std::string>::const_iterator it = lang.begin(); - it != lang.end(); ++it) { - if (*it == "ASM_MASM") { + for (std::string const& it : lang) { + if (it == "ASM_MASM") { this->MasmEnabled = true; } } @@ -146,7 +143,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 +222,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); @@ -249,10 +246,8 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() stampListFile += stampList; std::string stampFile; cmGeneratedFileStream fout(stampListFile.c_str()); - for (std::vector<cmLocalGenerator*>::const_iterator gi = - generators.begin(); - gi != generators.end(); ++gi) { - stampFile = (*gi)->GetMakefile()->GetCurrentBinaryDirectory(); + for (cmLocalGenerator const* gi : generators) { + stampFile = gi->GetMakefile()->GetCurrentBinaryDirectory(); stampFile += "/"; stampFile += cmake::GetCMakeFilesDirectoryPostSlash(); stampFile += "generate.stamp"; @@ -323,10 +318,9 @@ void cmGlobalVisualStudio8Generator::AddExtraIDETargets() const std::vector<cmGeneratorTarget*>& tgts = this->LocalGenerators[i]->GetGeneratorTargets(); // All targets depend on the build-system check target. - for (std::vector<cmGeneratorTarget*>::const_iterator ti = tgts.begin(); - ti != tgts.end(); ++ti) { - if ((*ti)->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) { - (*ti)->Target->AddUtility(CMAKE_CHECK_BUILD_SYSTEM_TARGET); + for (cmGeneratorTarget const* ti : tgts) { + if (ti->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) { + ti->Target->AddUtility(CMAKE_CHECK_BUILD_SYSTEM_TARGET); } } } @@ -337,10 +331,9 @@ void cmGlobalVisualStudio8Generator::WriteSolutionConfigurations( std::ostream& fout, std::vector<std::string> const& configs) { fout << "\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n"; - for (std::vector<std::string>::const_iterator i = configs.begin(); - i != configs.end(); ++i) { - fout << "\t\t" << *i << "|" << this->GetPlatformName() << " = " << *i - << "|" << this->GetPlatformName() << "\n"; + for (std::string const& i : configs) { + fout << "\t\t" << i << "|" << this->GetPlatformName() << " = " << i << "|" + << this->GetPlatformName() << "\n"; } fout << "\tEndGlobalSection\n"; } @@ -352,35 +345,34 @@ void cmGlobalVisualStudio8Generator::WriteProjectConfigurations( std::string const& platformMapping) { std::string guid = this->GetGUID(name); - for (std::vector<std::string>::const_iterator i = configs.begin(); - i != configs.end(); ++i) { + for (std::string const& i : configs) { std::vector<std::string> mapConfig; - const char* dstConfig = i->c_str(); + const char* dstConfig = i.c_str(); if (target.GetProperty("EXTERNAL_MSPROJECT")) { if (const char* m = target.GetProperty("MAP_IMPORTED_CONFIG_" + - cmSystemTools::UpperCase(*i))) { + cmSystemTools::UpperCase(i))) { cmSystemTools::ExpandListArgument(m, mapConfig); if (!mapConfig.empty()) { dstConfig = mapConfig[0].c_str(); } } } - fout << "\t\t{" << guid << "}." << *i << "|" << this->GetPlatformName() + fout << "\t\t{" << guid << "}." << i << "|" << this->GetPlatformName() << ".ActiveCfg = " << dstConfig << "|" << (!platformMapping.empty() ? platformMapping : this->GetPlatformName()) << "\n"; std::set<std::string>::const_iterator ci = - configsPartOfDefaultBuild.find(*i); + configsPartOfDefaultBuild.find(i); if (!(ci == configsPartOfDefaultBuild.end())) { - fout << "\t\t{" << guid << "}." << *i << "|" << this->GetPlatformName() + fout << "\t\t{" << guid << "}." << i << "|" << this->GetPlatformName() << ".Build.0 = " << dstConfig << "|" << (!platformMapping.empty() ? platformMapping : this->GetPlatformName()) << "\n"; } if (this->NeedsDeploy(target.GetType())) { - fout << "\t\t{" << guid << "}." << *i << "|" << this->GetPlatformName() + fout << "\t\t{" << guid << "}." << i << "|" << this->GetPlatformName() << ".Deploy.0 = " << dstConfig << "|" << (!platformMapping.empty() ? platformMapping : this->GetPlatformName()) @@ -410,12 +402,11 @@ void cmGlobalVisualStudio8Generator::WriteProjectDepends( { TargetDependSet const& unordered = this->GetTargetDirectDepends(gt); OrderedTargetDependSet depends(unordered, std::string()); - for (OrderedTargetDependSet::const_iterator i = depends.begin(); - i != depends.end(); ++i) { - if ((*i)->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + for (cmTargetDepend const& i : depends) { + if (i->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } - std::string guid = this->GetGUID((*i)->GetName().c_str()); + std::string guid = this->GetGUID(i->GetName()); fout << "\t\t{" << guid << "} = {" << guid << "}\n"; } } @@ -424,11 +415,9 @@ bool cmGlobalVisualStudio8Generator::NeedLinkLibraryDependencies( cmGeneratorTarget* target) { // Look for utility dependencies that magically link. - for (std::set<std::string>::const_iterator ui = - target->GetUtilities().begin(); - ui != target->GetUtilities().end(); ++ui) { + for (std::string const& ui : target->GetUtilities()) { if (cmGeneratorTarget* depTarget = - target->GetLocalGenerator()->FindGeneratorTargetToUse(ui->c_str())) { + target->GetLocalGenerator()->FindGeneratorTargetToUse(ui)) { if (depTarget->GetType() != cmStateEnums::INTERFACE_LIBRARY && depTarget->GetProperty("EXTERNAL_MSPROJECT")) { // This utility dependency names an external .vcproj target. diff --git a/Source/cmGlobalVisualStudio8Generator.h b/Source/cmGlobalVisualStudio8Generator.h index 4723b83..af83e4f 100644 --- a/Source/cmGlobalVisualStudio8Generator.h +++ b/Source/cmGlobalVisualStudio8Generator.h @@ -18,42 +18,42 @@ public: static cmGlobalGeneratorFactory* NewFactory(); ///! Get the name for the generator. - virtual std::string GetName() const { return this->Name; } + std::string GetName() const override { return this->Name; } /** Get the name of the main stamp list file. */ static std::string GetGenerateStampList(); - virtual void EnableLanguage(std::vector<std::string> const& languages, - cmMakefile*, bool optional); + void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*, + bool optional) override; virtual void AddPlatformDefinitions(cmMakefile* mf); - virtual bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf); + bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf) override; /** * Override Configure and Generate to add the build-system check * target. */ - virtual void Configure(); + void Configure() override; /** * Where does this version of Visual Studio look for macros for the * current user? Returns the empty string if this version of Visual * Studio does not implement support for VB macros. */ - virtual std::string GetUserMacrosDirectory(); + std::string GetUserMacrosDirectory() override; /** * What is the reg key path to "vsmacros" for this version of Visual * Studio? */ - virtual std::string GetUserMacrosRegKeyBase(); + std::string GetUserMacrosRegKeyBase() override; /** Return true if the target project file should have the option LinkLibraryDependencies and link to .sln dependencies. */ - virtual bool NeedLinkLibraryDependencies(cmGeneratorTarget* target); + bool NeedLinkLibraryDependencies(cmGeneratorTarget* target) override; /** Return true if building for Windows CE */ - virtual bool TargetsWindowsCE() const + bool TargetsWindowsCE() const override { return !this->WindowsCEVersion.empty(); } @@ -62,12 +62,12 @@ public: bool IsExpressEdition() const { return this->ExpressEdition; } protected: - virtual void AddExtraIDETargets(); - virtual const char* GetIDEVersion() { return "8.0"; } + void AddExtraIDETargets() override; + const char* GetIDEVersion() override { return "8.0"; } - virtual std::string FindDevEnvCommand(); + std::string FindDevEnvCommand() override; - virtual bool VSLinksDependencies() const { return false; } + bool VSLinksDependencies() const override { return false; } bool AddCheckTarget(); @@ -75,18 +75,18 @@ protected: virtual bool NeedsDeploy(cmStateEnums::TargetType type) const; static cmIDEFlagTable const* GetExtraFlagTableVS8(); - virtual void WriteSLNHeader(std::ostream& fout); - virtual void WriteSolutionConfigurations( - std::ostream& fout, std::vector<std::string> const& configs); - virtual void WriteProjectConfigurations( + void WriteSLNHeader(std::ostream& fout) override; + void WriteSolutionConfigurations( + std::ostream& fout, std::vector<std::string> const& configs) override; + void WriteProjectConfigurations( std::ostream& fout, const std::string& name, cmGeneratorTarget const& target, std::vector<std::string> const& configs, const std::set<std::string>& configsPartOfDefaultBuild, - const std::string& platformMapping = ""); - virtual bool ComputeTargetDepends(); - virtual void WriteProjectDepends(std::ostream& fout, const std::string& name, - const char* path, - const cmGeneratorTarget* t); + const std::string& platformMapping = "") override; + bool ComputeTargetDepends() override; + void WriteProjectDepends(std::ostream& fout, const std::string& name, + const char* path, + const cmGeneratorTarget* t) override; bool UseFolderProperty(); diff --git a/Source/cmGlobalVisualStudio9Generator.cxx b/Source/cmGlobalVisualStudio9Generator.cxx index 0abb348..7ac3a6f 100644 --- a/Source/cmGlobalVisualStudio9Generator.cxx +++ b/Source/cmGlobalVisualStudio9Generator.cxx @@ -68,10 +68,8 @@ public: parser.ParseVersion("9.0"); const std::vector<std::string>& availablePlatforms = parser.GetAvailablePlatforms(); - for (std::vector<std::string>::const_iterator i = - availablePlatforms.begin(); - i != availablePlatforms.end(); ++i) { - names.push_back("Visual Studio 9 2008 " + *i); + for (std::string const& i : availablePlatforms) { + names.push_back("Visual Studio 9 2008 " + i); } } diff --git a/Source/cmGlobalVisualStudio9Generator.h b/Source/cmGlobalVisualStudio9Generator.h index fbc1f5d..37efb9c 100644 --- a/Source/cmGlobalVisualStudio9Generator.h +++ b/Source/cmGlobalVisualStudio9Generator.h @@ -21,23 +21,23 @@ public: * Try to determine system information such as shared library * extension, pthreads, byte order etc. */ - virtual void WriteSLNHeader(std::ostream& fout); + void WriteSLNHeader(std::ostream& fout) override; /** * Where does this version of Visual Studio look for macros for the * current user? Returns the empty string if this version of Visual * Studio does not implement support for VB macros. */ - virtual std::string GetUserMacrosDirectory(); + std::string GetUserMacrosDirectory() override; /** * What is the reg key path to "vsmacros" for this version of Visual * Studio? */ - virtual std::string GetUserMacrosRegKeyBase(); + std::string GetUserMacrosRegKeyBase() override; protected: - virtual const char* GetIDEVersion() { return "9.0"; } + const char* GetIDEVersion() override { return "9.0"; } private: class Factory; friend class Factory; diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index 0651536..a4570e1 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" @@ -58,16 +61,15 @@ void cmGlobalVisualStudioGenerator::AddExtraIDETargets() const char* no_working_dir = 0; std::vector<std::string> no_depends; cmCustomCommandLines no_commands; - std::map<std::string, std::vector<cmLocalGenerator*>>::iterator it; - for (it = this->ProjectMap.begin(); it != this->ProjectMap.end(); ++it) { - std::vector<cmLocalGenerator*>& gen = it->second; + for (auto const& it : this->ProjectMap) { + std::vector<cmLocalGenerator*> const& gen = it.second; // add the ALL_BUILD to the first local generator of each project if (!gen.empty()) { // 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); @@ -80,14 +82,10 @@ void cmGlobalVisualStudioGenerator::AddExtraIDETargets() } // Now make all targets depend on the ALL_BUILD target - for (std::vector<cmLocalGenerator*>::iterator i = gen.begin(); - i != gen.end(); ++i) { - const std::vector<cmGeneratorTarget*>& targets = - (*i)->GetGeneratorTargets(); - for (std::vector<cmGeneratorTarget*>::const_iterator t = - targets.begin(); - t != targets.end(); ++t) { - cmGeneratorTarget* tgt = *t; + for (cmLocalGenerator const* i : gen) { + std::vector<cmGeneratorTarget*> const& targets = + i->GetGeneratorTargets(); + for (cmGeneratorTarget* tgt : targets) { if (tgt->GetType() == cmStateEnums::GLOBAL_TARGET || tgt->IsImported()) { continue; @@ -103,15 +101,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( @@ -249,10 +238,9 @@ void cmGlobalVisualStudioGenerator::FillLinkClosure( { if (linked.insert(target).second) { TargetDependSet const& depends = this->GetTargetDirectDepends(target); - for (TargetDependSet::const_iterator di = depends.begin(); - di != depends.end(); ++di) { - if (di->IsLink()) { - this->FillLinkClosure(*di, linked); + for (cmTargetDepend const& di : depends) { + if (di.IsLink()) { + this->FillLinkClosure(di, linked); } } } @@ -281,10 +269,9 @@ void cmGlobalVisualStudioGenerator::FollowLinkDepends( // Static library targets do not list their link dependencies so // we must follow them transitively now. TargetDependSet const& depends = this->GetTargetDirectDepends(target); - for (TargetDependSet::const_iterator di = depends.begin(); - di != depends.end(); ++di) { - if (di->IsLink()) { - this->FollowLinkDepends(*di, linked); + for (cmTargetDepend const& di : depends) { + if (di.IsLink()) { + this->FollowLinkDepends(di, linked); } } } @@ -295,17 +282,13 @@ bool cmGlobalVisualStudioGenerator::ComputeTargetDepends() if (!this->cmGlobalGenerator::ComputeTargetDepends()) { return false; } - std::map<std::string, std::vector<cmLocalGenerator*>>::iterator it; - for (it = this->ProjectMap.begin(); it != this->ProjectMap.end(); ++it) { - std::vector<cmLocalGenerator*>& gen = it->second; - for (std::vector<cmLocalGenerator*>::iterator i = gen.begin(); - i != gen.end(); ++i) { - const std::vector<cmGeneratorTarget*>& targets = - (*i)->GetGeneratorTargets(); - for (std::vector<cmGeneratorTarget*>::const_iterator ti = - targets.begin(); - ti != targets.end(); ++ti) { - this->ComputeVSTargetDepends(*ti); + for (auto const& it : this->ProjectMap) { + std::vector<cmLocalGenerator*> const& gen = it.second; + for (const cmLocalGenerator* i : gen) { + std::vector<cmGeneratorTarget*> const& targets = + i->GetGeneratorTargets(); + for (cmGeneratorTarget* ti : targets) { + this->ComputeVSTargetDepends(ti); } } } @@ -355,22 +338,20 @@ void cmGlobalVisualStudioGenerator::ComputeVSTargetDepends( // due to behavior (2), but they do not really need to. std::set<cmGeneratorTarget const*> linkDepends; if (target->GetType() != cmStateEnums::STATIC_LIBRARY) { - for (TargetDependSet::const_iterator di = depends.begin(); - di != depends.end(); ++di) { - cmTargetDepend dep = *di; + for (cmTargetDepend const& di : depends) { + cmTargetDepend dep = di; if (dep.IsLink()) { - this->FollowLinkDepends(*di, linkDepends); + this->FollowLinkDepends(di, linkDepends); } } } // Collect explicit util dependencies (add_dependencies). std::set<cmGeneratorTarget const*> utilDepends; - for (TargetDependSet::const_iterator di = depends.begin(); - di != depends.end(); ++di) { - cmTargetDepend dep = *di; + for (cmTargetDepend const& di : depends) { + cmTargetDepend dep = di; if (dep.IsUtil()) { - this->FollowLinkDepends(*di, utilDepends); + this->FollowLinkDepends(di, utilDepends); } } @@ -382,16 +363,12 @@ void cmGlobalVisualStudioGenerator::ComputeVSTargetDepends( } // Emit link dependencies. - for (std::set<cmGeneratorTarget const*>::iterator di = linkDepends.begin(); - di != linkDepends.end(); ++di) { - cmGeneratorTarget const* dep = *di; + for (cmGeneratorTarget const* dep : linkDepends) { vsTargetDepend.insert(dep->GetName()); } // Emit util dependencies. Possibly use intermediate targets. - for (std::set<cmGeneratorTarget const*>::iterator di = utilDepends.begin(); - di != utilDepends.end(); ++di) { - cmGeneratorTarget const* dgt = *di; + for (cmGeneratorTarget const* dgt : utilDepends) { if (allowLinkable || !VSLinkable(dgt) || linked.count(dgt)) { // Direct dependency allowed. vsTargetDepend.insert(dgt->GetName()); @@ -821,9 +798,8 @@ cmGlobalVisualStudioGenerator::OrderedTargetDependSet::OrderedTargetDependSet( TargetSet const& targets, std::string const& first) : derived(TargetCompare(first)) { - for (TargetSet::const_iterator it = targets.begin(); it != targets.end(); - ++it) { - this->insert(*it); + for (cmGeneratorTarget const* it : targets) { + this->insert(it); } } @@ -857,10 +833,8 @@ void cmGlobalVisualStudioGenerator::AddSymbolExportCommand( std::vector<cmSourceFile const*> objectSources; gt->GetObjectSources(objectSources, configName); std::map<cmSourceFile const*, std::string> mapping; - for (std::vector<cmSourceFile const*>::const_iterator it = - objectSources.begin(); - it != objectSources.end(); ++it) { - mapping[*it]; + for (cmSourceFile const* it : objectSources) { + mapping[it]; } gt->LocalGenerator->ComputeObjectFilenames(mapping, gt); std::string obj_dir = gt->ObjectDirectory; @@ -885,12 +859,10 @@ void cmGlobalVisualStudioGenerator::AddSymbolExportCommand( if (mdi->WindowsExportAllSymbols) { std::vector<std::string> objs; - for (std::vector<cmSourceFile const*>::const_iterator it = - objectSources.begin(); - it != objectSources.end(); ++it) { + for (cmSourceFile const* it : objectSources) { // Find the object file name corresponding to this source file. std::map<cmSourceFile const*, std::string>::const_iterator map_it = - mapping.find(*it); + mapping.find(it); // It must exist because we populated the mapping just above. assert(!map_it->second.empty()); std::string objFile = obj_dir + map_it->second; @@ -898,15 +870,12 @@ void cmGlobalVisualStudioGenerator::AddSymbolExportCommand( } std::vector<cmSourceFile const*> externalObjectSources; gt->GetExternalObjects(externalObjectSources, configName); - for (std::vector<cmSourceFile const*>::const_iterator it = - externalObjectSources.begin(); - it != externalObjectSources.end(); ++it) { - objs.push_back((*it)->GetFullPath()); + for (cmSourceFile const* it : externalObjectSources) { + objs.push_back(it->GetFullPath()); } - for (std::vector<std::string>::iterator it = objs.begin(); - it != objs.end(); ++it) { - std::string objFile = *it; + for (std::string const& it : objs) { + std::string objFile = it; // replace $(ConfigurationName) in the object names cmSystemTools::ReplaceString(objFile, this->GetCMakeCFGIntDir(), configName.c_str()); @@ -916,10 +885,8 @@ void cmGlobalVisualStudioGenerator::AddSymbolExportCommand( } } - for (std::vector<cmSourceFile const*>::const_iterator i = - mdi->Sources.begin(); - i != mdi->Sources.end(); ++i) { - fout << (*i)->GetFullPath() << "\n"; + for (cmSourceFile const* i : mdi->Sources) { + fout << i->GetFullPath() << "\n"; } cmCustomCommandLines commandLines; @@ -928,3 +895,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); + 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..75b7f22 100644 --- a/Source/cmGlobalVisualStudioGenerator.h +++ b/Source/cmGlobalVisualStudioGenerator.h @@ -96,11 +96,13 @@ public: /** Return true if the generated build tree may contain multiple builds. i.e. "Can I build Debug and Release in the same tree?" */ - virtual bool IsMultiConfig() const { return true; } + bool IsMultiConfig() const override { return true; } /** Return true if building for Windows CE */ virtual bool TargetsWindowsCE() const { return false; } + bool IsIncludeExternalMSProjectSupported() const override { return true; } + class TargetSet : public std::set<cmGeneratorTarget const*> { }; @@ -120,8 +122,8 @@ public: bool FindMakeProgram(cmMakefile*) override; - virtual std::string ExpandCFGIntDir(const std::string& str, - const std::string& config) const; + std::string ExpandCFGIntDir(const std::string& str, + const std::string& config) const override; void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const; @@ -131,8 +133,11 @@ 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(); + void AddExtraIDETargets() override; // Does this VS version link targets to each other if there are // dependencies in the SLN file? This was done for VS versions @@ -141,7 +146,7 @@ protected: virtual const char* GetIDEVersion() = 0; - virtual bool ComputeTargetDepends(); + bool ComputeTargetDepends() override; class VSDependSet : public std::set<std::string> { }; diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index c79ee47..d3f5aac 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" @@ -171,7 +176,7 @@ cmGlobalGenerator* cmGlobalXCodeGenerator::Factory::CreateGlobalGenerator( std::string versionFile; { std::string out; - std::string::size_type pos; + std::string::size_type pos = 0; if (cmSystemTools::RunSingleCommand("xcode-select --print-path", &out, nullptr, nullptr, nullptr, cmSystemTools::OUTPUT_NONE) && @@ -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; @@ -422,14 +459,18 @@ void cmGlobalXCodeGenerator::AddExtraTargets( // Add ZERO_CHECK bool regenerate = !mf->IsOn("CMAKE_SUPPRESS_REGENERATION"); - if (regenerate) { + bool generateTopLevelProjectOnly = + mf->IsOn("CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY"); + bool isTopLevel = + !root->GetStateSnapshot().GetBuildsystemDirectoryParent().IsValid(); + if (regenerate && (isTopLevel || !generateTopLevelProjectOnly)) { this->CreateReRunCMakeFile(root, gens); 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 +483,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 +519,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); } } } @@ -512,14 +546,14 @@ void cmGlobalXCodeGenerator::CreateReRunCMakeFile( makefileStream.SetCopyIfDifferent(true); makefileStream << "# Generated by CMake, DO NOT EDIT\n\n"; + makefileStream << "TARGETS:= \n"; makefileStream << "empty:= \n"; 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(); @@ -647,9 +681,56 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFileFromPath( return buildFile; } +class XCodeGeneratorExpressionInterpreter + : public cmGeneratorExpressionInterpreter +{ + CM_DISABLE_COPY(XCodeGeneratorExpressionInterpreter) + +public: + XCodeGeneratorExpressionInterpreter(cmSourceFile* sourceFile, + cmLocalGenerator* localGenerator, + cmGeneratorTarget* generatorTarget, + const std::string& lang) + : cmGeneratorExpressionInterpreter(localGenerator, generatorTarget, + "NO-PER-CONFIG-SUPPORT-IN-XCODE", + generatorTarget->GetName(), lang) + , SourceFile(sourceFile) + { + } + + using cmGeneratorExpressionInterpreter::Evaluate; + + const char* Evaluate(const char* expression, const std::string& property) + { + const char* processed = + this->cmGeneratorExpressionInterpreter::Evaluate(expression, property); + if (this->GetCompiledGeneratorExpression() + .GetHadContextSensitiveCondition()) { + std::ostringstream e; + /* clang-format off */ + e << + "Xcode does not support per-config per-source " << property << ":\n" + " " << expression << "\n" + "specified for source:\n" + " " << this->SourceFile->GetFullPath() << "\n"; + /* clang-format on */ + this->GetLocalGenerator()->IssueMessage(cmake::FATAL_ERROR, e.str()); + } + + return processed; + } + +private: + cmSourceFile* SourceFile = nullptr; +}; + cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile( cmLocalGenerator* lg, cmSourceFile* sf, cmGeneratorTarget* gtgt) { + std::string lang = this->CurrentLocalGenerator->GetSourceFileLanguage(*sf); + + XCodeGeneratorExpressionInterpreter genexInterpreter(sf, lg, gtgt, lang); + // Add flags from target and source file properties. std::string flags; const char* srcfmt = sf->GetProperty("Fortran_FORMAT"); @@ -663,31 +744,24 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile( default: break; } - if (const char* cflags = sf->GetProperty("COMPILE_FLAGS")) { - cmGeneratorExpression ge; - std::string configName = "NO-PER-CONFIG-SUPPORT-IN-XCODE"; - std::unique_ptr<cmCompiledGeneratorExpression> compiledExpr = - ge.Parse(cflags); - const char* processed = - compiledExpr->Evaluate(lg, configName, false, gtgt); - if (compiledExpr->GetHadContextSensitiveCondition()) { - std::ostringstream e; - /* clang-format off */ - e << - "Xcode does not support per-config per-source COMPILE_FLAGS:\n" - " " << cflags << "\n" - "specified for source:\n" - " " << sf->GetFullPath() << "\n"; - /* clang-format on */ - lg->IssueMessage(cmake::FATAL_ERROR, e.str()); - } - lg->AppendFlags(flags, processed); + const std::string COMPILE_FLAGS("COMPILE_FLAGS"); + if (const char* cflags = sf->GetProperty(COMPILE_FLAGS)) { + lg->AppendFlags(flags, genexInterpreter.Evaluate(cflags, COMPILE_FLAGS)); + } + const std::string COMPILE_OPTIONS("COMPILE_OPTIONS"); + if (const char* coptions = sf->GetProperty(COMPILE_OPTIONS)) { + lg->AppendCompileOptions( + flags, genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS)); } // Add per-source definitions. BuildObjectListOrString flagsBuild(this, false); - this->AppendDefines(flagsBuild, sf->GetProperty("COMPILE_DEFINITIONS"), - true); + const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS"); + if (const char* compile_defs = sf->GetProperty(COMPILE_DEFINITIONS)) { + this->AppendDefines( + flagsBuild, genexInterpreter.Evaluate(compile_defs, COMPILE_DEFINITIONS), + true); + } if (!flagsBuild.IsEmpty()) { if (!flags.empty()) { flags += ' '; @@ -695,7 +769,15 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile( flags += flagsBuild.GetString(); } - std::string lang = this->CurrentLocalGenerator->GetSourceFileLanguage(*sf); + // Add per-source include directories. + std::vector<std::string> includes; + const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES"); + if (const char* cincludes = sf->GetProperty(INCLUDE_DIRECTORIES)) { + lg->AppendIncludeDirectories( + includes, genexInterpreter.Evaluate(cincludes, INCLUDE_DIRECTORIES), + *sf); + } + lg->AppendFlags(flags, lg->GetIncludeFlags(includes, gtgt, lang, true)); cmXCodeObject* buildFile = this->CreateXCodeSourceFileFromPath(sf->GetFullPath(), gtgt, lang, sf); @@ -728,9 +810,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 +1006,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 +1041,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 +1056,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 +1077,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 +1095,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 +1172,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 +1190,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") { - if (gtgt->Target->GetMakefile()->PlatformIsAppleIos()) { - ostr << mit->first; + ostr << keySources.first; + } else if (keySources.first != "MacOS") { + if (gtgt->Target->GetMakefile()->PlatformIsAppleEmbedded()) { + ostr << keySources.first; } else { // dstPath in bundles is relative to Contents/MacOS - ostr << "../" << mit->first; + ostr << "../" << keySources.first; } } copyFilesBuildPhase->AddAttribute("dstPath", @@ -1122,10 +1205,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 +1220,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 +1235,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 +1282,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 +1306,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 +1407,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 +1441,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 +1565,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(); @@ -1652,6 +1723,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, gtgt->GetName().c_str()); return; } + std::string const& langForPreprocessor = llang; if (gtgt->IsIPOEnabled(llang, configName)) { const char* ltoValue = @@ -1672,7 +1744,10 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, this->AppendDefines(ppDefs, exportMacro); } std::vector<std::string> targetDefines; - gtgt->GetCompileDefinitions(targetDefines, configName, "C"); + if (!langForPreprocessor.empty()) { + gtgt->GetCompileDefinitions(targetDefines, configName, + langForPreprocessor); + } this->AppendDefines(ppDefs, targetDefines); buildSettings->AddAttribute("GCC_PREPROCESSOR_DEFINITIONS", ppDefs.CreateList()); @@ -1945,8 +2020,10 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, const bool emitSystemIncludes = this->XcodeVersion >= 83; std::vector<std::string> includes; - this->CurrentLocalGenerator->GetIncludeDirectories(includes, gtgt, "C", - configName); + if (!langForPreprocessor.empty()) { + this->CurrentLocalGenerator->GetIncludeDirectories( + includes, gtgt, langForPreprocessor, configName); + } std::set<std::string> emitted; emitted.insert("/System/Library/Frameworks"); @@ -1976,8 +2053,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 +2218,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 +2278,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 +2332,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 +2616,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 +2637,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 +2652,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 +2678,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 +2704,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 +2730,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 +2741,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 +2753,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 +2768,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 +2856,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 +2971,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 +2981,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); } @@ -2941,7 +3018,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( buildSettings->AddAttribute("ARCHS", this->CreateString(archs)); } if (deploymentTarget && *deploymentTarget) { - buildSettings->AddAttribute("MACOSX_DEPLOYMENT_TARGET", + buildSettings->AddAttribute(GetDeploymentPlatform(root->GetMakefile()), this->CreateString(deploymentTarget)); } if (!this->GeneratorToolset.empty()) { @@ -2971,16 +3048,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 +3171,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 +3181,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 +3194,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 +3215,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"; @@ -3177,11 +3244,11 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget( << this->ConvertToRelativeForMake(tfull.c_str()) << "\n"; // if building for more than one architecture - // then remove those exectuables as well + // then remove those executables as well 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 +3279,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 +3301,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 +3325,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 +3344,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)) { @@ -3386,7 +3447,8 @@ void cmGlobalXCodeGenerator::GetDocumentation(cmDocumentationEntry& entry) entry.Brief = "Generate Xcode project files."; } -std::string cmGlobalXCodeGenerator::ConvertToRelativeForMake(const char* p) +std::string cmGlobalXCodeGenerator::ConvertToRelativeForMake( + std::string const& p) { return cmSystemTools::ConvertToOutputPath(p); } @@ -3480,7 +3542,7 @@ void cmGlobalXCodeGenerator::AppendDefines( } void cmGlobalXCodeGenerator::AppendFlag(std::string& flags, - std::string const& flag) + std::string const& flag) const { // Short-circuit for an empty flag. if (flag.empty()) { @@ -3512,17 +3574,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; } } @@ -3570,7 +3632,7 @@ bool cmGlobalXCodeGenerator::UseEffectivePlatformName(cmMakefile* mf) const "XCODE_EMIT_EFFECTIVE_PLATFORM_NAME"); if (!epnValue) { - return mf->PlatformIsAppleIos(); + return mf->PlatformIsAppleEmbedded(); } return cmSystemTools::IsOn(epnValue); @@ -3592,3 +3654,24 @@ void cmGlobalXCodeGenerator::ComputeTargetObjectDirectory( dir += "/"; gt->ObjectDirectory = dir; } + +std::string cmGlobalXCodeGenerator::GetDeploymentPlatform(const cmMakefile* mf) +{ + switch (mf->GetAppleSDKType()) { + case cmMakefile::AppleSDK::AppleTVOS: + case cmMakefile::AppleSDK::AppleTVSimulator: + return "TVOS_DEPLOYMENT_TARGET"; + + case cmMakefile::AppleSDK::IPhoneOS: + case cmMakefile::AppleSDK::IPhoneSimulator: + return "IPHONEOS_DEPLOYMENT_TARGET"; + + case cmMakefile::AppleSDK::WatchOS: + case cmMakefile::AppleSDK::WatchSimulator: + return "WATCHOS_DEPLOYMENT_TARGET"; + + case cmMakefile::AppleSDK::MacOS: + default: + return "MACOSX_DEPLOYMENT_TARGET"; + } +} diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index e9ca91c..b45887e 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. @@ -97,7 +104,7 @@ public: bool ShouldStripResourcePath(cmMakefile*) const override; bool SetGeneratorToolset(std::string const& ts, cmMakefile* mf) override; - void AppendFlag(std::string& flags, std::string const& flag); + void AppendFlag(std::string& flags, std::string const& flag) const; protected: void AddExtraIDETargets() override; @@ -112,7 +119,7 @@ private: std::string XCodeEscapePath(const std::string& p); std::string RelativeToSource(const char* p); std::string RelativeToBinary(const char* p); - std::string ConvertToRelativeForMake(const char* p); + std::string ConvertToRelativeForMake(std::string const& p); void CreateCustomCommands(cmXCodeObject* buildPhases, cmXCodeObject* sourceBuildPhase, cmXCodeObject* headerBuildPhase, @@ -247,6 +254,8 @@ private: const std::string& configName, const cmGeneratorTarget* t) const; + static std::string GetDeploymentPlatform(const cmMakefile* mf); + void ComputeArchitectures(cmMakefile* mf); void ComputeObjectDirArch(cmMakefile* mf); diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx index e684f5e..1bbfbe0 100644 --- a/Source/cmGraphVizWriter.cxx +++ b/Source/cmGraphVizWriter.cxx @@ -224,11 +224,11 @@ void cmGraphVizWriter::ReadSettings(const char* settingsFileName, ignoreTargetsRegExVector); for (std::string const& currentRegexString : ignoreTargetsRegExVector) { cmsys::RegularExpression currentRegex; - if (!currentRegex.compile(currentRegexString.c_str())) { + if (!currentRegex.compile(currentRegexString)) { std::cerr << "Could not compile bad regex \"" << currentRegexString << "\"" << std::endl; } - this->TargetsToIgnoreRegex.push_back(currentRegex); + this->TargetsToIgnoreRegex.push_back(std::move(currentRegex)); } } } diff --git a/Source/cmIDEOptions.cxx b/Source/cmIDEOptions.cxx index 5e872d2..354b757 100644 --- a/Source/cmIDEOptions.cxx +++ b/Source/cmIDEOptions.cxx @@ -13,6 +13,7 @@ cmIDEOptions::cmIDEOptions() { this->DoingDefine = false; this->AllowDefine = true; + this->DoingInclude = false; this->AllowSlash = false; this->DoingFollowing = 0; for (int i = 0; i < FlagTableCount; ++i) { @@ -33,6 +34,13 @@ void cmIDEOptions::HandleFlag(const char* flag) return; } + // If the last option was -I then this option is the include directory. + if (this->DoingInclude) { + this->DoingInclude = false; + this->Includes.push_back(flag); + return; + } + // If the last option expected a following value, this is it. if (this->DoingFollowing) { this->FlagMapUpdate(this->DoingFollowing, flag); @@ -53,6 +61,17 @@ void cmIDEOptions::HandleFlag(const char* flag) } return; } + // Look for include directory. + if (this->AllowInclude && flag[1] == 'I') { + if (flag[2] == '\0') { + // The next argument will have the include directory. + this->DoingInclude = true; + } else { + // Store this include directory. + this->Includes.push_back(flag + 2); + } + return; + } // Look through the available flag tables. bool flag_handled = false; @@ -155,12 +174,35 @@ std::vector<std::string> const& cmIDEOptions::GetDefines() const return this->Defines; } -void cmIDEOptions::AddFlag(const char* flag, const char* value) +void cmIDEOptions::AddInclude(const std::string& include) +{ + this->Includes.push_back(include); +} + +void cmIDEOptions::AddIncludes(const char* includes) +{ + if (includes) { + // Expand the list of includes. + cmSystemTools::ExpandListArgument(includes, this->Includes); + } +} +void cmIDEOptions::AddIncludes(const std::vector<std::string>& includes) +{ + this->Includes.insert(this->Includes.end(), includes.begin(), + includes.end()); +} + +std::vector<std::string> const& cmIDEOptions::GetIncludes() const +{ + return this->Includes; +} + +void cmIDEOptions::AddFlag(std::string const& flag, std::string const& value) { this->FlagMap[flag] = value; } -void cmIDEOptions::AddFlag(const char* flag, +void cmIDEOptions::AddFlag(std::string const& flag, std::vector<std::string> const& value) { this->FlagMap[flag] = value; @@ -185,7 +227,7 @@ void cmIDEOptions::AppendFlagString(std::string const& flag, this->FlagMap[flag].append_with_space(value); } -void cmIDEOptions::RemoveFlag(const char* flag) +void cmIDEOptions::RemoveFlag(std::string const& flag) { this->FlagMap.erase(flag); } @@ -195,12 +237,13 @@ bool cmIDEOptions::HasFlag(std::string const& flag) const return this->FlagMap.find(flag) != this->FlagMap.end(); } -const char* cmIDEOptions::GetFlag(const char* flag) +const char* cmIDEOptions::GetFlag(std::string const& flag) const { // This method works only for single-valued flags! - std::map<std::string, FlagValue>::iterator i = this->FlagMap.find(flag); - if (i != this->FlagMap.end() && i->second.size() == 1) { + std::map<std::string, FlagValue>::const_iterator i = + this->FlagMap.find(flag); + if (i != this->FlagMap.cend() && i->second.size() == 1) { return i->second[0].c_str(); } - return 0; + return nullptr; } diff --git a/Source/cmIDEOptions.h b/Source/cmIDEOptions.h index af03128..54cb524 100644 --- a/Source/cmIDEOptions.h +++ b/Source/cmIDEOptions.h @@ -20,21 +20,26 @@ public: cmIDEOptions(); virtual ~cmIDEOptions(); - // Store definitions and flags. + // Store definitions, includes and flags. void AddDefine(const std::string& define); void AddDefines(const char* defines); void AddDefines(const std::vector<std::string>& defines); std::vector<std::string> const& GetDefines() const; - void AddFlag(const char* flag, const char* value); - void AddFlag(const char* flag, std::vector<std::string> const& value); + void AddInclude(const std::string& includes); + void AddIncludes(const char* includes); + void AddIncludes(const std::vector<std::string>& includes); + std::vector<std::string> const& GetIncludes() const; + + void AddFlag(std::string const& flag, std::string const& value); + void AddFlag(std::string const& flag, std::vector<std::string> const& value); void AppendFlag(std::string const& flag, std::string const& value); void AppendFlag(std::string const& flag, std::vector<std::string> const& value); void AppendFlagString(std::string const& flag, std::string const& value); - void RemoveFlag(const char* flag); + void RemoveFlag(std::string const& flag); bool HasFlag(std::string const& flag) const; - const char* GetFlag(const char* flag); + const char* GetFlag(std::string const& flag) const; protected: // create a map of xml tags to the values they should have in the output @@ -76,8 +81,13 @@ protected: // Preprocessor definitions. std::vector<std::string> Defines; + // Include directories. + std::vector<std::string> Includes; + bool DoingDefine; bool AllowDefine; + bool DoingInclude; + bool AllowInclude; bool AllowSlash; cmIDEFlagTable const* DoingFollowing; enum diff --git a/Source/cmIncludeCommand.cxx b/Source/cmIncludeCommand.cxx index cd4d850..b42d75e 100644 --- a/Source/cmIncludeCommand.cxx +++ b/Source/cmIncludeCommand.cxx @@ -63,7 +63,7 @@ bool cmIncludeCommand::InitialPass(std::vector<std::string> const& args, return true; } - if (!cmSystemTools::FileIsFullPath(fname.c_str())) { + if (!cmSystemTools::FileIsFullPath(fname)) { // Not a path. Maybe module. std::string module = fname; module += ".cmake"; @@ -112,7 +112,7 @@ bool cmIncludeCommand::InitialPass(std::vector<std::string> const& args, std::string listFile = cmSystemTools::CollapseFullPath( fname, this->Makefile->GetCurrentSourceDirectory()); - if (optional && !cmSystemTools::FileExists(listFile.c_str())) { + if (optional && !cmSystemTools::FileExists(listFile)) { if (!resultVarName.empty()) { this->Makefile->AddDefinition(resultVarName, "NOTFOUND"); } diff --git a/Source/cmIncludeDirectoryCommand.cxx b/Source/cmIncludeDirectoryCommand.cxx index 4c30607..4f80fb8 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 " @@ -97,7 +97,7 @@ void cmIncludeDirectoryCommand::GetIncludes(const std::string& arg, std::string inc = arg.substr(lastPos, pos); this->NormalizeInclude(inc); if (!inc.empty()) { - incs.push_back(inc); + incs.push_back(std::move(inc)); } } lastPos = pos + 1; @@ -105,7 +105,7 @@ void cmIncludeDirectoryCommand::GetIncludes(const std::string& arg, std::string inc = arg.substr(lastPos); this->NormalizeInclude(inc); if (!inc.empty()) { - incs.push_back(inc); + incs.push_back(std::move(inc)); } } @@ -123,7 +123,7 @@ void cmIncludeDirectoryCommand::NormalizeInclude(std::string& inc) if (!cmSystemTools::IsOff(inc.c_str())) { cmSystemTools::ConvertToUnixSlashes(inc); - if (!cmSystemTools::FileIsFullPath(inc.c_str())) { + if (!cmSystemTools::FileIsFullPath(inc)) { if (!StartsWithGeneratorExpression(inc)) { std::string tmp = this->Makefile->GetCurrentSourceDirectory(); tmp += "/"; diff --git a/Source/cmIncludeExternalMSProjectCommand.cxx b/Source/cmIncludeExternalMSProjectCommand.cxx index bd16b1d..85e8cd3 100644 --- a/Source/cmIncludeExternalMSProjectCommand.cxx +++ b/Source/cmIncludeExternalMSProjectCommand.cxx @@ -3,6 +3,7 @@ #include "cmIncludeExternalMSProjectCommand.h" #ifdef _WIN32 +#include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmStateTypes.h" #include "cmSystemTools.h" @@ -22,7 +23,9 @@ bool cmIncludeExternalMSProjectCommand::InitialPass( } // only compile this for win32 to avoid coverage errors #ifdef _WIN32 - if (this->Makefile->GetDefinition("WIN32")) { + if (this->Makefile->GetDefinition("WIN32") || + this->Makefile->GetGlobalGenerator() + ->IsIncludeExternalMSProjectSupported()) { enum Doing { DoingNone, diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 685fc67..394f976 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -5,6 +5,7 @@ #include "cmsys/Glob.hxx" #include <sstream> #include <stddef.h> +#include <utility> #include "cmAlgorithms.h" #include "cmCommandArgumentsHelper.h" @@ -154,7 +155,7 @@ bool cmInstallCommand::HandleScriptMode(std::vector<std::string> const& args) } else if (doing_script) { doing_script = false; std::string script = arg; - if (!cmSystemTools::FileIsFullPath(script.c_str())) { + if (!cmSystemTools::FileIsFullPath(script)) { script = this->Makefile->GetCurrentSourceDirectory(); script += "/"; script += arg; @@ -1044,14 +1045,14 @@ bool cmInstallCommand::HandleDirectoryMode( // Convert this directory to a full path. std::string dir = args[i]; std::string::size_type gpos = cmGeneratorExpression::Find(dir); - if (gpos != 0 && !cmSystemTools::FileIsFullPath(dir.c_str())) { + if (gpos != 0 && !cmSystemTools::FileIsFullPath(dir)) { dir = this->Makefile->GetCurrentSourceDirectory(); dir += "/"; dir += args[i]; } // Make sure the name is a directory. - if (cmSystemTools::FileExists(dir.c_str()) && + if (cmSystemTools::FileExists(dir) && !cmSystemTools::FileIsDirectory(dir)) { std::ostringstream e; e << args[0] << " given non-directory \"" << args[i] @@ -1061,7 +1062,7 @@ bool cmInstallCommand::HandleDirectoryMode( } // Store the directory for installation. - dirs.push_back(dir); + dirs.push_back(std::move(dir)); } else if (doing == DoingConfigurations) { configurations.push_back(args[i]); } else if (doing == DoingDestination) { @@ -1133,7 +1134,7 @@ bool cmInstallCommand::HandleDirectoryMode( // Support installing an empty directory. if (dirs.empty() && destination) { - dirs.push_back(""); + dirs.emplace_back(); } // Check if there is something to do. @@ -1374,7 +1375,7 @@ bool cmInstallCommand::MakeFilesFullPath( for (std::string const& relFile : relFiles) { std::string file = relFile; std::string::size_type gpos = cmGeneratorExpression::Find(file); - if (gpos != 0 && !cmSystemTools::FileIsFullPath(file.c_str())) { + if (gpos != 0 && !cmSystemTools::FileIsFullPath(file)) { file = this->Makefile->GetCurrentSourceDirectory(); file += "/"; file += relFile; @@ -1388,7 +1389,7 @@ bool cmInstallCommand::MakeFilesFullPath( return false; } // Store the file for installation. - absFiles.push_back(file); + absFiles.push_back(std::move(file)); } return true; } diff --git a/Source/cmInstallCommandArguments.cxx b/Source/cmInstallCommandArguments.cxx index 12abac8..7b79ab5 100644 --- a/Source/cmInstallCommandArguments.cxx +++ b/Source/cmInstallCommandArguments.cxx @@ -4,6 +4,8 @@ #include "cmSystemTools.h" +#include <utility> + // Table of valid permissions. const char* cmInstallCommandArguments::PermissionsTable[] = { "OWNER_READ", "OWNER_WRITE", "OWNER_EXECUTE", "GROUP_READ", @@ -200,6 +202,6 @@ void cmInstallCommandIncludesArgument::Parse( for (; it != args->end(); ++it) { std::string dir = *it; cmSystemTools::ConvertToUnixSlashes(dir); - this->IncludeDirs.push_back(dir); + this->IncludeDirs.push_back(std::move(dir)); } } diff --git a/Source/cmInstallDirectoryGenerator.cxx b/Source/cmInstallDirectoryGenerator.cxx index e4209bd..b569b73 100644 --- a/Source/cmInstallDirectoryGenerator.cxx +++ b/Source/cmInstallDirectoryGenerator.cxx @@ -72,7 +72,7 @@ void cmInstallDirectoryGenerator::GenerateScriptForConfig( // Make sure all dirs have absolute paths. cmMakefile const& mf = *this->LocalGenerator->GetMakefile(); for (std::string& d : dirs) { - if (!cmSystemTools::FileIsFullPath(d.c_str())) { + if (!cmSystemTools::FileIsFullPath(d)) { d = std::string(mf.GetCurrentSourceDirectory()) + "/" + d; } } diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx index fdd231c..5990f30 100644 --- a/Source/cmInstallExportGenerator.cxx +++ b/Source/cmInstallExportGenerator.cxx @@ -132,7 +132,7 @@ void cmInstallExportGenerator::GenerateScript(std::ostream& os) // Create the temporary directory in which to store the files. this->ComputeTempDir(); - cmSystemTools::MakeDirectory(this->TempDir.c_str()); + cmSystemTools::MakeDirectory(this->TempDir); // Construct a temporary location for the file. this->MainImportFile = this->TempDir; diff --git a/Source/cmInstallFilesCommand.cxx b/Source/cmInstallFilesCommand.cxx index 4a3b620..4dde18f 100644 --- a/Source/cmInstallFilesCommand.cxx +++ b/Source/cmInstallFilesCommand.cxx @@ -30,8 +30,7 @@ bool cmInstallFilesCommand::InitialPass(std::vector<std::string> const& args, for (std::vector<std::string>::const_iterator s = args.begin() + 2; s != args.end(); ++s) { // Find the source location for each file listed. - std::string f = this->FindInstallSource(s->c_str()); - this->Files.push_back(f); + this->Files.push_back(this->FindInstallSource(s->c_str())); } this->CreateInstallGenerator(); } else { @@ -138,11 +137,11 @@ std::string cmInstallFilesCommand::FindInstallSource(const char* name) const ts += "/"; ts += name; - if (cmSystemTools::FileExists(tb.c_str())) { + if (cmSystemTools::FileExists(tb)) { // The file exists in the binary tree. Use it. return tb; } - if (cmSystemTools::FileExists(ts.c_str())) { + if (cmSystemTools::FileExists(ts)) { // The file exists in the source tree. Use it. return ts; } diff --git a/Source/cmInstallGenerator.cxx b/Source/cmInstallGenerator.cxx index 4d01978..53ac716 100644 --- a/Source/cmInstallGenerator.cxx +++ b/Source/cmInstallGenerator.cxx @@ -55,7 +55,7 @@ void cmInstallGenerator::AddInstallRule( break; } os << indent; - if (cmSystemTools::FileIsFullPath(dest.c_str())) { + if (cmSystemTools::FileIsFullPath(dest)) { os << "list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n"; os << indent << " \""; for (std::vector<std::string>::const_iterator fi = files.begin(); @@ -165,7 +165,7 @@ std::string cmInstallGenerator::ConvertToAbsoluteDestination( std::string const& dest) const { std::string result; - if (!dest.empty() && !cmSystemTools::FileIsFullPath(dest.c_str())) { + if (!dest.empty() && !cmSystemTools::FileIsFullPath(dest)) { result = "${CMAKE_INSTALL_PREFIX}/"; } result += dest; diff --git a/Source/cmInstallProgramsCommand.cxx b/Source/cmInstallProgramsCommand.cxx index 5ee81fb..f01a4c1 100644 --- a/Source/cmInstallProgramsCommand.cxx +++ b/Source/cmInstallProgramsCommand.cxx @@ -109,11 +109,11 @@ std::string cmInstallProgramsCommand::FindInstallSource(const char* name) const ts += "/"; ts += name; - if (cmSystemTools::FileExists(tb.c_str())) { + if (cmSystemTools::FileExists(tb)) { // The file exists in the binary tree. Use it. return tb; } - if (cmSystemTools::FileExists(ts.c_str())) { + if (cmSystemTools::FileExists(ts)) { // The file exists in the source tree. Use it. return ts; } diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx index b964794..a9b4908 100644 --- a/Source/cmInstallTargetGenerator.cxx +++ b/Source/cmInstallTargetGenerator.cxx @@ -132,8 +132,8 @@ void cmInstallTargetGenerator::GenerateScriptForConfig( if (this->ImportLibrary) { std::string from1 = fromDirConfig + targetNameImport; std::string to1 = toDir + targetNameImport; - filesFrom.push_back(from1); - filesTo.push_back(to1); + filesFrom.push_back(std::move(from1)); + filesTo.push_back(std::move(to1)); std::string targetNameImportLib; if (this->Target->GetImplibGNUtoMS(targetNameImport, targetNameImportLib)) { @@ -167,7 +167,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig( to1 += "."; to1 += ext; to1 += "/"; - if (!mf->PlatformIsAppleIos()) { + if (!mf->PlatformIsAppleEmbedded()) { to1 += "Contents/MacOS/"; } to1 += targetName; @@ -176,13 +176,13 @@ void cmInstallTargetGenerator::GenerateScriptForConfig( if (targetNameReal != targetName) { std::string from2 = fromDirConfig + targetNameReal; std::string to2 = toDir += targetNameReal; - filesFrom.push_back(from2); - filesTo.push_back(to2); + filesFrom.push_back(std::move(from2)); + filesTo.push_back(std::move(to2)); } } - filesFrom.push_back(from1); - filesTo.push_back(to1); + filesFrom.push_back(std::move(from1)); + filesTo.push_back(std::move(to1)); } } else { std::string targetName; @@ -198,8 +198,8 @@ void cmInstallTargetGenerator::GenerateScriptForConfig( std::string from1 = fromDirConfig + targetNameImport; std::string to1 = toDir + targetNameImport; - filesFrom.push_back(from1); - filesTo.push_back(to1); + filesFrom.push_back(std::move(from1)); + filesTo.push_back(std::move(to1)); std::string targetNameImportLib; if (this->Target->GetImplibGNUtoMS(targetNameImport, targetNameImportLib)) { @@ -223,8 +223,8 @@ void cmInstallTargetGenerator::GenerateScriptForConfig( // Tweaks apply to the binary inside the bundle. std::string to1 = toDir + targetNameReal; - filesFrom.push_back(from1); - filesTo.push_back(to1); + filesFrom.push_back(std::move(from1)); + filesTo.push_back(std::move(to1)); } else if (this->Target->IsCFBundleOnApple()) { // Install the whole app bundle directory. type = cmInstallType_DIRECTORY; @@ -235,8 +235,8 @@ void cmInstallTargetGenerator::GenerateScriptForConfig( std::string from1 = fromDirConfig + targetNameBase; std::string to1 = toDir + targetName; - filesFrom.push_back(from1); - filesTo.push_back(to1); + filesFrom.push_back(std::move(from1)); + filesTo.push_back(std::move(to1)); } else { bool haveNamelink = false; @@ -796,7 +796,7 @@ void cmInstallTargetGenerator::AddUniversalInstallRule( { cmMakefile const* mf = this->Target->Target->GetMakefile(); - if (!mf->PlatformIsAppleIos() || !mf->IsOn("XCODE")) { + if (!mf->PlatformIsAppleEmbedded() || !mf->IsOn("XCODE")) { return; } diff --git a/Source/cmLinkDirectoriesCommand.cxx b/Source/cmLinkDirectoriesCommand.cxx index 98ab7e7..1371c53 100644 --- a/Source/cmLinkDirectoriesCommand.cxx +++ b/Source/cmLinkDirectoriesCommand.cxx @@ -29,7 +29,7 @@ void cmLinkDirectoriesCommand::AddLinkDir(std::string const& dir) { std::string unixPath = dir; cmSystemTools::ConvertToUnixSlashes(unixPath); - if (!cmSystemTools::FileIsFullPath(unixPath.c_str())) { + if (!cmSystemTools::FileIsFullPath(unixPath)) { bool convertToAbsolute = false; std::ostringstream e; /* clang-format off */ 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..64e634f 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -252,8 +252,7 @@ bool cmListFileParser::ParseFunction(const char* name, long line) bool cmListFileParser::AddArgument(cmListFileLexer_Token* token, cmListFileArgument::Delimiter delim) { - cmListFileArgument a(token->text, delim, token->line); - this->Function.Arguments.push_back(a); + this->Function.Arguments.emplace_back(token->text, delim, token->line); if (this->Separation == SeparationOkay) { return true; } @@ -438,6 +437,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/cmLoadCacheCommand.cxx b/Source/cmLoadCacheCommand.cxx index 32fdef5..b1fee8d 100644 --- a/Source/cmLoadCacheCommand.cxx +++ b/Source/cmLoadCacheCommand.cxx @@ -82,7 +82,7 @@ bool cmLoadCacheCommand::ReadWithPrefix(std::vector<std::string> const& args) // Make sure the cache file exists. std::string cacheFile = args[0] + "/CMakeCache.txt"; - if (!cmSystemTools::FileExists(cacheFile.c_str())) { + if (!cmSystemTools::FileExists(cacheFile)) { std::string e = "Cannot load cache file from " + cacheFile; this->SetError(e); return false; diff --git a/Source/cmLocalCommonGenerator.cxx b/Source/cmLocalCommonGenerator.cxx index 50ebfa1..5a43f2e 100644 --- a/Source/cmLocalCommonGenerator.cxx +++ b/Source/cmLocalCommonGenerator.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmLocalCommonGenerator.h" +#include <utility> #include <vector> #include "cmGeneratorTarget.h" @@ -76,3 +77,17 @@ std::string cmLocalCommonGenerator::GetTargetFortranFlags( return flags; } + +void cmLocalCommonGenerator::ComputeObjectFilenames( + std::map<cmSourceFile const*, std::string>& mapping, + cmGeneratorTarget const* gt) +{ + // Determine if these object files should use a custom extension + char const* custom_ext = gt->GetCustomObjectExtension(); + for (auto& si : mapping) { + cmSourceFile const* sf = si.first; + bool keptSourceExtension; + si.second = this->GetObjectFileNameWithoutTarget( + *sf, gt->ObjectDirectory, &keptSourceExtension, custom_ext); + } +} diff --git a/Source/cmLocalCommonGenerator.h b/Source/cmLocalCommonGenerator.h index a60573c..7b8e6fe 100644 --- a/Source/cmLocalCommonGenerator.h +++ b/Source/cmLocalCommonGenerator.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <map> #include <string> #include "cmLocalGenerator.h" @@ -12,6 +13,7 @@ class cmGeneratorTarget; class cmGlobalGenerator; class cmMakefile; +class cmSourceFile; /** \class cmLocalCommonGenerator * \brief Common infrastructure for Makefile and Ninja local generators. @@ -30,6 +32,10 @@ public: std::string GetTargetFortranFlags(cmGeneratorTarget const* target, std::string const& config) override; + void ComputeObjectFilenames( + std::map<cmSourceFile const*, std::string>& mapping, + cmGeneratorTarget const* gt = nullptr) override; + protected: std::string WorkingDirectory; diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 1a088ea..08f3c0f 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -16,6 +16,7 @@ #include "cmMakefile.h" #include "cmRulePlaceholderExpander.h" #include "cmSourceFile.h" +#include "cmSourceFileLocation.h" #include "cmState.h" #include "cmStateDirectory.h" #include "cmStateTypes.h" @@ -37,6 +38,7 @@ #include <sstream> #include <stdio.h> #include <string.h> +#include <unordered_set> #include <utility> #if defined(__HAIKU__) @@ -135,8 +137,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); @@ -205,7 +207,7 @@ void cmLocalGenerator::TraceDependencies() std::vector<std::string> configs; this->Makefile->GetConfigurations(configs); if (configs.empty()) { - configs.push_back(""); + configs.emplace_back(); } for (std::string const& c : configs) { this->GlobalGenerator->CreateEvaluationSourceFiles(c); @@ -222,7 +224,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 +240,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 +489,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(); @@ -534,14 +553,13 @@ void cmLocalGenerator::GenerateInstallRules() void cmLocalGenerator::AddGeneratorTarget(cmGeneratorTarget* gt) { this->GeneratorTargets.push_back(gt); - this->GeneratorTargetSearchIndex.insert( - std::pair<std::string, cmGeneratorTarget*>(gt->GetName(), gt)); + this->GeneratorTargetSearchIndex.emplace(gt->GetName(), gt); this->GlobalGenerator->IndexGeneratorTarget(gt); } void cmLocalGenerator::AddImportedGeneratorTarget(cmGeneratorTarget* gt) { - this->ImportedGeneratorTargets.push_back(gt); + this->ImportedGeneratorTargets.emplace(gt->GetName(), gt); this->GlobalGenerator->IndexGeneratorTarget(gt); } @@ -550,22 +568,6 @@ void cmLocalGenerator::AddOwnedImportedGeneratorTarget(cmGeneratorTarget* gt) this->OwnedImportedGeneratorTargets.push_back(gt); } -struct NamedGeneratorTargetFinder -{ - NamedGeneratorTargetFinder(std::string const& name) - : Name(name) - { - } - - bool operator()(cmGeneratorTarget* tgt) - { - return tgt->GetName() == this->Name; - } - -private: - std::string Name; -}; - cmGeneratorTarget* cmLocalGenerator::FindLocalNonAliasGeneratorTarget( const std::string& name) const { @@ -583,7 +585,7 @@ void cmLocalGenerator::ComputeTargetManifest() std::vector<std::string> configNames; this->Makefile->GetConfigurations(configNames); if (configNames.empty()) { - configNames.push_back(""); + configNames.emplace_back(); } // Add our targets to the manifest for each configuration. @@ -604,7 +606,7 @@ bool cmLocalGenerator::ComputeTargetCompileFeatures() std::vector<std::string> configNames; this->Makefile->GetConfigurations(configNames); if (configNames.empty()) { - configNames.push_back(""); + configNames.emplace_back(); } // Process compile features of all targets. @@ -775,19 +777,14 @@ void cmLocalGenerator::AddCompileOptions(std::string& flags, if (const char* langFlagRegexStr = this->Makefile->GetDefinition(langFlagRegexVar)) { // Filter flags acceptable to this language. - cmsys::RegularExpression r(langFlagRegexStr); std::vector<std::string> opts; if (const char* targetFlags = target->GetProperty("COMPILE_FLAGS")) { cmSystemTools::ParseWindowsCommandLine(targetFlags, opts); } target->GetCompileOptions(opts, config, lang); - for (std::string const& opt : opts) { - if (r.find(opt.c_str())) { - // (Re-)Escape this flag. COMPILE_FLAGS were already parsed - // as a command line above, and COMPILE_OPTIONS are escaped. - this->AppendFlagEscape(flags, opt); - } - } + // (Re-)Escape these flags. COMPILE_FLAGS were already parsed + // as a command line above, and COMPILE_OPTIONS are escaped. + this->AppendCompileOptions(flags, opts, langFlagRegexStr); } else { // Use all flags. if (const char* targetFlags = target->GetProperty("COMPILE_FLAGS")) { @@ -796,10 +793,8 @@ void cmLocalGenerator::AddCompileOptions(std::string& flags, } std::vector<std::string> opts; target->GetCompileOptions(opts, config, lang); - for (std::string const& opt : opts) { - // COMPILE_OPTIONS are escaped. - this->AppendFlagEscape(flags, opt); - } + // COMPILE_OPTIONS are escaped. + this->AppendCompileOptions(flags, opts); } for (auto const& it : target->GetMaxLanguageStandards()) { @@ -894,7 +889,7 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs, for (std::string const& i : impDirVec) { std::string d = rootPath + i; cmSystemTools::ConvertToUnixSlashes(d); - emitted.insert(d); + emitted.insert(std::move(d)); if (!stripImplicitInclDirs) { implicitDirs.push_back(i); } @@ -909,8 +904,8 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs, // Support putting all the in-project include directories first if // it is requested by the project. if (this->Makefile->IsOn("CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE")) { - const char* topSourceDir = this->GetState()->GetSourceDirectory(); - const char* topBinaryDir = this->GetState()->GetBinaryDirectory(); + std::string const &topSourceDir = this->GetState()->GetSourceDirectory(), + &topBinaryDir = this->GetState()->GetBinaryDirectory(); for (std::string const& i : includes) { // Emit this directory only if it is a subdirectory of the // top-level source or binary tree. @@ -1383,11 +1378,10 @@ void cmLocalGenerator::AddLanguageFlagsForLinking( cmGeneratorTarget* cmLocalGenerator::FindGeneratorTargetToUse( const std::string& name) const { - std::vector<cmGeneratorTarget*>::const_iterator imported = std::find_if( - this->ImportedGeneratorTargets.begin(), - this->ImportedGeneratorTargets.end(), NamedGeneratorTargetFinder(name)); + GeneratorTargetMap::const_iterator imported = + this->ImportedGeneratorTargets.find(name); if (imported != this->ImportedGeneratorTargets.end()) { - return *imported; + return imported->second; } if (cmGeneratorTarget* t = this->FindLocalNonAliasGeneratorTarget(name)) { @@ -1422,7 +1416,7 @@ bool cmLocalGenerator::GetRealDependency(const std::string& inName, if (cmGeneratorTarget* target = this->FindGeneratorTargetToUse(name)) { // make sure it is not just a coincidence that the target name // found is part of the inName - if (cmSystemTools::FileIsFullPath(inName.c_str())) { + if (cmSystemTools::FileIsFullPath(inName)) { std::string tLocation; if (target->GetType() >= cmStateEnums::EXECUTABLE && target->GetType() <= cmStateEnums::MODULE_LIBRARY) { @@ -1466,7 +1460,7 @@ bool cmLocalGenerator::GetRealDependency(const std::string& inName, } // The name was not that of a CMake target. It must name a file. - if (cmSystemTools::FileIsFullPath(inName.c_str())) { + if (cmSystemTools::FileIsFullPath(inName)) { // This is a full path. Return it as given. dep = inName; return true; @@ -1859,7 +1853,7 @@ void cmLocalGenerator::AddConfigVariableFlags(std::string& flags, } void cmLocalGenerator::AppendFlags(std::string& flags, - const std::string& newFlags) + const std::string& newFlags) const { if (!newFlags.empty()) { if (!flags.empty()) { @@ -1869,7 +1863,8 @@ void cmLocalGenerator::AppendFlags(std::string& flags, } } -void cmLocalGenerator::AppendFlags(std::string& flags, const char* newFlags) +void cmLocalGenerator::AppendFlags(std::string& flags, + const char* newFlags) const { if (newFlags && *newFlags) { this->AppendFlags(flags, std::string(newFlags)); @@ -1877,7 +1872,7 @@ void cmLocalGenerator::AppendFlags(std::string& flags, const char* newFlags) } void cmLocalGenerator::AppendFlagEscape(std::string& flags, - const std::string& rawFlag) + const std::string& rawFlag) const { this->AppendFlags(flags, this->EscapeForShell(rawFlag)); } @@ -1913,6 +1908,87 @@ void cmLocalGenerator::AppendIPOLinkerFlags(std::string& flags, } } +void cmLocalGenerator::AppendCompileOptions(std::string& options, + const char* options_list, + const char* regex) const +{ + // Short-circuit if there are no options. + if (!options_list) { + return; + } + + // Expand the list of options. + std::vector<std::string> options_vec; + cmSystemTools::ExpandListArgument(options_list, options_vec); + this->AppendCompileOptions(options, options_vec, regex); +} + +void cmLocalGenerator::AppendCompileOptions( + std::string& options, const std::vector<std::string>& options_vec, + const char* regex) const +{ + if (regex != nullptr) { + // Filter flags upon specified reges. + cmsys::RegularExpression r(regex); + + for (std::string const& opt : options_vec) { + if (r.find(opt.c_str())) { + this->AppendFlagEscape(options, opt); + } + } + } else { + for (std::string const& opt : options_vec) { + this->AppendFlagEscape(options, opt); + } + } +} + +void cmLocalGenerator::AppendIncludeDirectories( + std::vector<std::string>& includes, const char* includes_list, + const cmSourceFile& sourceFile) const +{ + // Short-circuit if there are no includes. + if (!includes_list) { + return; + } + + // Expand the list of includes. + std::vector<std::string> includes_vec; + cmSystemTools::ExpandListArgument(includes_list, includes_vec); + this->AppendIncludeDirectories(includes, includes_vec, sourceFile); +} + +void cmLocalGenerator::AppendIncludeDirectories( + std::vector<std::string>& includes, + const std::vector<std::string>& includes_vec, + const cmSourceFile& sourceFile) const +{ + std::unordered_set<std::string> uniqueIncludes; + + for (const std::string& include : includes_vec) { + if (!cmSystemTools::FileIsFullPath(include)) { + std::ostringstream e; + e << "Found relative path while evaluating include directories of " + "\"" + << sourceFile.GetLocation().GetName() << "\":\n \"" << include + << "\"\n"; + + this->IssueMessage(cmake::FATAL_ERROR, e.str()); + return; + } + + std::string inc = include; + + if (!cmSystemTools::IsOff(inc.c_str())) { + cmSystemTools::ConvertToUnixSlashes(inc); + } + + if (uniqueIncludes.insert(inc).second) { + includes.push_back(std::move(inc)); + } + } +} + void cmLocalGenerator::AppendDefines(std::set<std::string>& defines, const char* defines_list) const { @@ -2313,14 +2389,14 @@ std::string cmLocalGenerator::GetObjectFileNameWithoutTarget( std::string relFromSource = this->ConvertToRelativePath(this->GetCurrentSourceDirectory(), fullPath); assert(!relFromSource.empty()); - bool relSource = !cmSystemTools::FileIsFullPath(relFromSource.c_str()); + bool relSource = !cmSystemTools::FileIsFullPath(relFromSource); bool subSource = relSource && relFromSource[0] != '.'; // Try referencing the source relative to the binary tree. std::string relFromBinary = this->ConvertToRelativePath(this->GetCurrentBinaryDirectory(), fullPath); assert(!relFromBinary.empty()); - bool relBinary = !cmSystemTools::FileIsFullPath(relFromBinary.c_str()); + bool relBinary = !cmSystemTools::FileIsFullPath(relFromBinary); bool subBinary = relBinary && relFromBinary[0] != '.'; // Select a nice-looking reference to the source file to construct @@ -2339,7 +2415,7 @@ std::string cmLocalGenerator::GetObjectFileNameWithoutTarget( // if it is still a full path check for the try compile case // try compile never have in source sources, and should not // have conflicting source file names in the same target - if (cmSystemTools::FileIsFullPath(objectName.c_str())) { + if (cmSystemTools::FileIsFullPath(objectName)) { if (this->GetGlobalGenerator()->GetCMakeInstance()->GetIsInTryCompile()) { objectName = cmSystemTools::GetFilenameName(source.GetFullPath()); } @@ -2397,12 +2473,12 @@ cmake* cmLocalGenerator::GetCMakeInstance() const return this->GlobalGenerator->GetCMakeInstance(); } -const char* cmLocalGenerator::GetSourceDirectory() const +std::string const& cmLocalGenerator::GetSourceDirectory() const { return this->GetCMakeInstance()->GetHomeDirectory(); } -const char* cmLocalGenerator::GetBinaryDirectory() const +std::string const& cmLocalGenerator::GetBinaryDirectory() const { return this->GetCMakeInstance()->GetHomeOutputDirectory(); } @@ -2541,13 +2617,13 @@ void cmLocalGenerator::GenerateAppleInfoPList(cmGeneratorTarget* target, // Find the Info.plist template. const char* in = target->GetProperty("MACOSX_BUNDLE_INFO_PLIST"); std::string inFile = (in && *in) ? in : "MacOSXBundleInfo.plist.in"; - if (!cmSystemTools::FileIsFullPath(inFile.c_str())) { + if (!cmSystemTools::FileIsFullPath(inFile)) { std::string inMod = this->Makefile->GetModulesFile(inFile.c_str()); if (!inMod.empty()) { inFile = inMod; } } - if (!cmSystemTools::FileExists(inFile.c_str(), true)) { + if (!cmSystemTools::FileExists(inFile, true)) { std::ostringstream e; e << "Target " << target->GetName() << " Info.plist template \"" << inFile << "\" could not be found."; @@ -2579,13 +2655,13 @@ void cmLocalGenerator::GenerateFrameworkInfoPList( // Find the Info.plist template. const char* in = target->GetProperty("MACOSX_FRAMEWORK_INFO_PLIST"); std::string inFile = (in && *in) ? in : "MacOSXFrameworkInfo.plist.in"; - if (!cmSystemTools::FileIsFullPath(inFile.c_str())) { + if (!cmSystemTools::FileIsFullPath(inFile)) { std::string inMod = this->Makefile->GetModulesFile(inFile.c_str()); if (!inMod.empty()) { inFile = inMod; } } - if (!cmSystemTools::FileExists(inFile.c_str(), true)) { + if (!cmSystemTools::FileExists(inFile, true)) { std::ostringstream e; e << "Target " << target->GetName() << " Info.plist template \"" << inFile << "\" could not be found."; diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 4a7d2ca..533ac56 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -118,10 +118,11 @@ public: cmGeneratorTarget const* target, const std::string& lang); ///! Append flags to a string. - virtual void AppendFlags(std::string& flags, const std::string& newFlags); - virtual void AppendFlags(std::string& flags, const char* newFlags); + virtual void AppendFlags(std::string& flags, + const std::string& newFlags) const; + virtual void AppendFlags(std::string& flags, const char* newFlags) const; virtual void AppendFlagEscape(std::string& flags, - const std::string& rawFlag); + const std::string& rawFlag) const; void AppendIPOLinkerFlags(std::string& flags, cmGeneratorTarget* target, const std::string& config, const std::string& lang); @@ -138,11 +139,6 @@ public: return this->GeneratorTargets; } - const std::vector<cmGeneratorTarget*>& GetImportedGeneratorTargets() const - { - return this->ImportedGeneratorTargets; - } - void AddGeneratorTarget(cmGeneratorTarget* gt); void AddImportedGeneratorTarget(cmGeneratorTarget* gt); void AddOwnedImportedGeneratorTarget(cmGeneratorTarget* gt); @@ -152,6 +148,23 @@ public: cmGeneratorTarget* FindGeneratorTargetToUse(const std::string& name) const; /** + * Process a list of include directories + */ + void AppendIncludeDirectories(std::vector<std::string>& includes, + const char* includes_list, + const cmSourceFile& sourceFile) const; + void AppendIncludeDirectories(std::vector<std::string>& includes, + std::string const& includes_list, + const cmSourceFile& sourceFile) const + { + this->AppendIncludeDirectories(includes, includes_list.c_str(), + sourceFile); + } + void AppendIncludeDirectories(std::vector<std::string>& includes, + const std::vector<std::string>& includes_vec, + const cmSourceFile& sourceFile) const; + + /** * Encode a list of preprocessor definitions for the compiler * command line. */ @@ -166,6 +179,22 @@ public: const std::vector<std::string>& defines_vec) const; /** + * Encode a list of compile options for the compiler + * command line. + */ + void AppendCompileOptions(std::string& options, const char* options_list, + const char* regex = nullptr) const; + void AppendCompileOptions(std::string& options, + std::string const& options_list, + const char* regex = nullptr) const + { + this->AppendCompileOptions(options, options_list.c_str(), regex); + } + void AppendCompileOptions(std::string& options, + const std::vector<std::string>& options_vec, + const char* regex = nullptr) const; + + /** * Join a set of defines into a definesString with a space separator. */ void JoinDefines(const std::set<std::string>& defines, @@ -258,8 +287,8 @@ public: cmake* GetCMakeInstance() const; - const char* GetSourceDirectory() const; - const char* GetBinaryDirectory() const; + std::string const& GetSourceDirectory() const; + std::string const& GetBinaryDirectory() const; const char* GetCurrentBinaryDirectory() const; const char* GetCurrentSourceDirectory() const; @@ -360,7 +389,7 @@ protected: std::vector<cmGeneratorTarget*> GeneratorTargets; std::set<cmGeneratorTarget const*> WarnCMP0063; - std::vector<cmGeneratorTarget*> ImportedGeneratorTargets; + GeneratorTargetMap ImportedGeneratorTargets; std::vector<cmGeneratorTarget*> OwnedImportedGeneratorTargets; std::map<std::string, std::string> AliasTargets; diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 477ce51..8c889fc 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -207,6 +207,9 @@ void cmLocalNinjaGenerator::WritePools(std::ostream& os) const char* jobpools = this->GetCMakeInstance()->GetState()->GetGlobalProperty("JOB_POOLS"); + if (!jobpools) { + jobpools = this->GetMakefile()->GetDefinition("CMAKE_JOB_POOLS"); + } if (jobpools) { cmGlobalNinjaGenerator::WriteComment( os, "Pools defined by global property JOB_POOLS"); @@ -243,20 +246,6 @@ void cmLocalNinjaGenerator::WriteNinjaFilesInclusion(std::ostream& os) os << "\n"; } -void cmLocalNinjaGenerator::ComputeObjectFilenames( - std::map<cmSourceFile const*, std::string>& mapping, - cmGeneratorTarget const* gt) -{ - // Determine if these object files should use a custom extension - char const* custom_ext = gt->GetCustomObjectExtension(); - for (auto& si : mapping) { - cmSourceFile const* sf = si.first; - bool keptSourceExtension; - si.second = this->GetObjectFileNameWithoutTarget( - *sf, gt->ObjectDirectory, &keptSourceExtension, custom_ext); - } -} - void cmLocalNinjaGenerator::WriteProcessedMakefile(std::ostream& os) { cmGlobalNinjaGenerator::WriteDivider(os); diff --git a/Source/cmLocalNinjaGenerator.h b/Source/cmLocalNinjaGenerator.h index bb16899..95d8a61 100644 --- a/Source/cmLocalNinjaGenerator.h +++ b/Source/cmLocalNinjaGenerator.h @@ -23,7 +23,6 @@ class cmGlobalGenerator; class cmGlobalNinjaGenerator; class cmMakefile; class cmRulePlaceholderExpander; -class cmSourceFile; class cmake; /** @@ -74,10 +73,6 @@ public: void AppendCustomCommandDeps(cmCustomCommandGenerator const& ccg, cmNinjaDeps& ninjaDeps); - void ComputeObjectFilenames( - std::map<cmSourceFile const*, std::string>& mapping, - cmGeneratorTarget const* gt = nullptr) override; - protected: std::string ConvertToIncludeReference( std::string const& path, diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index e26182a..ddd8cc4 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -150,20 +150,6 @@ void cmLocalUnixMakefileGenerator3::ComputeHomeRelativeOutputPath() } } -void cmLocalUnixMakefileGenerator3::ComputeObjectFilenames( - std::map<cmSourceFile const*, std::string>& mapping, - cmGeneratorTarget const* gt) -{ - // Determine if these object files should use a custom extension - char const* custom_ext = gt->GetCustomObjectExtension(); - for (auto& si : mapping) { - cmSourceFile const* sf = si.first; - bool keptSourceExtension; - si.second = this->GetObjectFileNameWithoutTarget( - *sf, gt->ObjectDirectory, &keptSourceExtension, custom_ext); - } -} - void cmLocalUnixMakefileGenerator3::GetLocalObjectFiles( std::map<std::string, LocalObjectInfo>& localObjectFiles) { @@ -186,12 +172,12 @@ void cmLocalUnixMakefileGenerator3::GetLocalObjectFiles( bool hasSourceExtension = true; std::string objectName = this->GetObjectFileNameWithoutTarget(*sf, dir, &hasSourceExtension); - if (cmSystemTools::FileIsFullPath(objectName.c_str())) { + if (cmSystemTools::FileIsFullPath(objectName)) { objectName = cmSystemTools::GetFilenameName(objectName); } LocalObjectInfo& info = localObjectFiles[objectName]; info.HasSourceExtension = hasSourceExtension; - info.push_back(LocalObjectEntry(gt, sf->GetLanguage())); + info.emplace_back(gt, sf->GetLanguage()); } } } @@ -539,8 +525,7 @@ void cmLocalUnixMakefileGenerator3::WriteMakeRule( // Construct the left hand side of the rule. std::string tgt = cmSystemTools::ConvertToOutputPath( - this->MaybeConvertToRelativePath(this->GetBinaryDirectory(), target) - .c_str()); + this->MaybeConvertToRelativePath(this->GetBinaryDirectory(), target)); const char* space = ""; if (tgt.size() == 1) { @@ -568,7 +553,7 @@ void cmLocalUnixMakefileGenerator3::WriteMakeRule( for (std::string const& depend : depends) { replace = depend; replace = cmSystemTools::ConvertToOutputPath( - this->MaybeConvertToRelativePath(binDir, replace).c_str()); + this->MaybeConvertToRelativePath(binDir, replace)); os << cmMakeSafe(tgt) << space << ": " << cmMakeSafe(replace) << "\n"; } } @@ -588,7 +573,7 @@ void cmLocalUnixMakefileGenerator3::WriteMakeRule( std::string cmLocalUnixMakefileGenerator3::MaybeConvertWatcomShellCommand( std::string const& cmd) { - if (this->IsWatcomWMake() && cmSystemTools::FileIsFullPath(cmd.c_str()) && + if (this->IsWatcomWMake() && cmSystemTools::FileIsFullPath(cmd) && cmd.find_first_of("( )") != std::string::npos) { // On Watcom WMake use the windows short path for the command // name. This is needed to avoid funny quoting problems on @@ -750,11 +735,11 @@ void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsTop( static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator); std::string hack = gg->GetEmptyRuleHackDepends(); if (!hack.empty()) { - no_depends.push_back(hack); + no_depends.push_back(std::move(hack)); } std::string hack_cmd = gg->GetEmptyRuleHackCommand(); if (!hack_cmd.empty()) { - no_commands.push_back(hack_cmd); + no_commands.push_back(std::move(hack_cmd)); } // Special symbolic target that never exists to force dependers to @@ -788,7 +773,7 @@ void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsBottom( std::vector<std::string> no_depends; std::vector<std::string> commands; - commands.push_back(runRule); + commands.push_back(std::move(runRule)); if (!this->IsRootMakefile()) { this->CreateCDCommand(commands, this->GetBinaryDirectory(), this->GetCurrentBinaryDirectory()); @@ -830,8 +815,8 @@ std::string cmLocalUnixMakefileGenerator3::GetRelativeTargetDirectory( return dir; } -void cmLocalUnixMakefileGenerator3::AppendFlags(std::string& flags, - const std::string& newFlags) +void cmLocalUnixMakefileGenerator3::AppendFlags( + std::string& flags, const std::string& newFlags) const { if (this->IsWatcomWMake() && !newFlags.empty()) { std::string newf = newFlags; @@ -845,7 +830,7 @@ void cmLocalUnixMakefileGenerator3::AppendFlags(std::string& flags, } void cmLocalUnixMakefileGenerator3::AppendFlags(std::string& flags, - const char* newFlags) + const char* newFlags) const { this->cmLocalGenerator::AppendFlags(flags, newFlags); } @@ -888,7 +873,7 @@ void cmLocalUnixMakefileGenerator3::AppendCustomDepend( // Lookup the real name of the dependency in case it is a CMake target. std::string dep; if (this->GetRealDependency(d, this->ConfigName, dep)) { - depends.push_back(dep); + depends.push_back(std::move(dep)); } } } @@ -1037,12 +1022,12 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( cmd = "echo >nul && " + cmd; } } - commands1.push_back(cmd); + commands1.push_back(std::move(cmd)); } } // Setup the proper working directory for the commands. - this->CreateCDCommand(commands1, dir.c_str(), relative); + this->CreateCDCommand(commands1, dir, relative); // push back the custom commands commands.insert(commands.end(), commands1.begin(), commands1.end()); @@ -1075,12 +1060,14 @@ void cmLocalUnixMakefileGenerator3::AppendCleanCommand( } fout << ")\n"; } - std::string remove = "$(CMAKE_COMMAND) -P "; - remove += this->ConvertToOutputFormat( - this->MaybeConvertToRelativePath(this->GetCurrentBinaryDirectory(), - cleanfile), - cmOutputConverter::SHELL); - commands.push_back(remove); + { + std::string remove = "$(CMAKE_COMMAND) -P "; + remove += this->ConvertToOutputFormat( + this->MaybeConvertToRelativePath(this->GetCurrentBinaryDirectory(), + cleanfile), + cmOutputConverter::SHELL); + commands.push_back(std::move(remove)); + } // For the main clean rule add per-language cleaning. if (!filename) { @@ -1158,10 +1145,10 @@ void cmLocalUnixMakefileGenerator3::AppendEcho( } cmd += this->EscapeForShell(line); } - commands.push_back(cmd); + commands.push_back(std::move(cmd)); } - // Reset the line to emtpy. + // Reset the line to empty. line.clear(); // Progress appears only on first line. @@ -1444,6 +1431,8 @@ bool cmLocalUnixMakefileGenerator3::ScanDependencies( } #ifdef CMAKE_BUILD_WITH_CMAKE else if (lang == "Fortran") { + ruleFileStream << "# Note that incremental build could trigger " + << "a call to cmake_copy_f90_mod on each re-build\n"; scanner = new cmDependsFortran(this); } else if (lang == "Java") { scanner = new cmDependsJava(); @@ -1486,8 +1475,8 @@ void cmLocalUnixMakefileGenerator3::CheckMultipleOutputs(bool verbose) // If the depender is missing then delete the dependee to make // sure both will be regenerated. - if (cmSystemTools::FileExists(dependee.c_str()) && - !cmSystemTools::FileExists(depender.c_str())) { + if (cmSystemTools::FileExists(dependee) && + !cmSystemTools::FileExists(depender)) { if (verbose) { std::ostringstream msg; msg << "Deleting primary custom command output \"" << dependee @@ -1673,13 +1662,15 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( commands.clear(); std::string cmakefileName = cmake::GetCMakeFilesDirectoryPostSlash(); cmakefileName += "Makefile.cmake"; - std::string runRule = - "$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"; - runRule += " --check-build-system "; - runRule += - this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL); - runRule += " 1"; - commands.push_back(runRule); + { + std::string runRule = + "$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"; + runRule += " --check-build-system "; + runRule += + this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL); + runRule += " 1"; + commands.push_back(std::move(runRule)); + } this->CreateCDCommand(commands, this->GetBinaryDirectory(), this->GetCurrentBinaryDirectory()); this->WriteMakeRule(ruleFileStream, "clear depends", "depend", depends, @@ -1836,7 +1827,7 @@ void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo( this->GetIncludeDirectories(includes, target, implicitLang.first, config); std::string binaryDir = this->GetState()->GetBinaryDirectory(); if (this->Makefile->IsOn("CMAKE_DEPENDS_IN_PROJECT_ONLY")) { - const char* sourceDir = this->GetState()->GetSourceDirectory(); + std::string const& sourceDir = this->GetState()->GetSourceDirectory(); cmEraseIf(includes, ::NotInProjectDir(sourceDir, binaryDir)); } for (std::string const& include : includes) { @@ -2037,7 +2028,7 @@ void cmLocalUnixMakefileGenerator3::AddImplicitDepends( } void cmLocalUnixMakefileGenerator3::CreateCDCommand( - std::vector<std::string>& commands, const char* tgtDir, + std::vector<std::string>& commands, std::string const& tgtDir, std::string const& relDir) { // do we need to cd? @@ -2064,7 +2055,7 @@ void cmLocalUnixMakefileGenerator3::CreateCDCommand( // Change back to the starting directory. cmd = cd_cmd; cmd += this->ConvertToOutputForExisting(relDir); - commands.push_back(cmd); + commands.push_back(std::move(cmd)); } else { // On UNIX we must construct a single shell command to change // directory and build because make resets the directory between diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h index b149524..bc72f1b 100644 --- a/Source/cmLocalUnixMakefileGenerator3.h +++ b/Source/cmLocalUnixMakefileGenerator3.h @@ -19,7 +19,6 @@ class cmCustomCommandGenerator; class cmGeneratorTarget; class cmGlobalGenerator; class cmMakefile; -class cmSourceFile; /** \class cmLocalUnixMakefileGenerator3 * \brief Write a LocalUnix makefiles. @@ -88,8 +87,9 @@ public: const std::string& tgt); // append flags to a string - void AppendFlags(std::string& flags, const std::string& newFlags) override; - void AppendFlags(std::string& flags, const char* newFlags) override; + void AppendFlags(std::string& flags, + const std::string& newFlags) const override; + void AppendFlags(std::string& flags, const char* newFlags) const override; // append an echo command enum EchoColor @@ -117,7 +117,8 @@ public: // create a command that cds to the start dir then runs the commands void CreateCDCommand(std::vector<std::string>& commands, - const char* targetDir, std::string const& relDir); + std::string const& targetDir, + std::string const& relDir); static std::string ConvertToQuotedOutputPath(const char* p, bool useWatcomQuote); @@ -251,10 +252,6 @@ protected: private: std::string MaybeConvertWatcomShellCommand(std::string const& cmd); - void ComputeObjectFilenames( - std::map<cmSourceFile const*, std::string>& mapping, - cmGeneratorTarget const* gt = nullptr) override; - friend class cmMakefileTargetGenerator; friend class cmMakefileExecutableTargetGenerator; friend class cmMakefileLibraryTargetGenerator; diff --git a/Source/cmLocalVisualStudio10Generator.cxx b/Source/cmLocalVisualStudio10Generator.cxx index 5e81514..2803d4a 100644 --- a/Source/cmLocalVisualStudio10Generator.cxx +++ b/Source/cmLocalVisualStudio10Generator.cxx @@ -64,20 +64,18 @@ cmLocalVisualStudio10Generator::~cmLocalVisualStudio10Generator() void cmLocalVisualStudio10Generator::Generate() { - const std::vector<cmGeneratorTarget*>& tgts = this->GetGeneratorTargets(); - for (std::vector<cmGeneratorTarget*>::const_iterator l = tgts.begin(); - l != tgts.end(); ++l) { - if ((*l)->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + for (cmGeneratorTarget* l : tgts) { + if (l->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } if (static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator) - ->TargetIsFortranOnly(*l)) { - this->CreateSingleVCProj((*l)->GetName().c_str(), *l); + ->TargetIsFortranOnly(l)) { + this->CreateSingleVCProj(l->GetName(), l); } else { cmVisualStudio10TargetGenerator tg( - *l, static_cast<cmGlobalVisualStudio10Generator*>( - this->GetGlobalGenerator())); + l, static_cast<cmGlobalVisualStudio10Generator*>( + this->GetGlobalGenerator())); tg.Generate(); } } diff --git a/Source/cmLocalVisualStudio10Generator.h b/Source/cmLocalVisualStudio10Generator.h index 4cd56dd..bcdc307 100644 --- a/Source/cmLocalVisualStudio10Generator.h +++ b/Source/cmLocalVisualStudio10Generator.h @@ -29,13 +29,13 @@ public: /** * Generate the makefile for this directory. */ - virtual void Generate(); - virtual void ReadAndStoreExternalGUID(const std::string& name, - const char* path); + void Generate() override; + void ReadAndStoreExternalGUID(const std::string& name, + const char* path) override; protected: - virtual const char* ReportErrorLabel() const; - virtual bool CustomCommandUseLocal() const { return true; } + const char* ReportErrorLabel() const override; + bool CustomCommandUseLocal() const override { return true; } private: }; diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index d8030b7..98b1c44 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -36,16 +36,14 @@ private: cmLocalVisualStudio7Generator* LocalGenerator; }; -extern cmVS7FlagTable cmLocalVisualStudio7GeneratorFlagTable[]; - -static void cmConvertToWindowsSlash(std::string& s) +class cmLocalVisualStudio7Generator::AllConfigSources { - std::string::size_type pos = 0; - while ((pos = s.find('/', pos)) != std::string::npos) { - s[pos] = '\\'; - pos++; - } -} +public: + std::vector<cmGeneratorTarget::AllConfigSource> Sources; + std::map<cmSourceFile const*, size_t> Index; +}; + +extern cmVS7FlagTable cmLocalVisualStudio7GeneratorFlagTable[]; cmLocalVisualStudio7Generator::cmLocalVisualStudio7Generator( cmGlobalGenerator* gg, cmMakefile* mf) @@ -63,14 +61,13 @@ void cmLocalVisualStudio7Generator::AddHelperCommands() { // Now create GUIDs for targets const std::vector<cmGeneratorTarget*>& tgts = this->GetGeneratorTargets(); - for (std::vector<cmGeneratorTarget*>::const_iterator l = tgts.begin(); - l != tgts.end(); ++l) { - if ((*l)->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + for (cmGeneratorTarget const* l : tgts) { + if (l->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } - const char* path = (*l)->GetProperty("EXTERNAL_MSPROJECT"); + const char* path = l->GetProperty("EXTERNAL_MSPROJECT"); if (path) { - this->ReadAndStoreExternalGUID((*l)->GetName().c_str(), path); + this->ReadAndStoreExternalGUID(l->GetName(), path); } } @@ -83,38 +80,14 @@ 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 // commands for targets in which no sources are built. Add dummy // rules to force these targets to build. 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) { + for (cmGeneratorTarget* l : tgts) { + if (l->GetType() == cmStateEnums::GLOBAL_TARGET) { std::vector<std::string> no_depends; cmCustomCommandLine force_command; force_command.push_back("cd"); @@ -125,12 +98,12 @@ void cmLocalVisualStudio7Generator::FixGlobalTargets() std::string force = this->GetCurrentBinaryDirectory(); force += cmake::GetCMakeFilesDirectory(); force += "/"; - force += (*l)->GetName(); + force += l->GetName(); force += "_force"; if (cmSourceFile* file = this->Makefile->AddCustomCommandToOutput( force.c_str(), no_depends, no_main_dependency, force_commands, " ", 0, true)) { - (*l)->AddSource(file->GetFullPath()); + l->AddSource(file->GetFullPath()); } } } @@ -142,8 +115,7 @@ void cmLocalVisualStudio7Generator::FixGlobalTargets() void cmLocalVisualStudio7Generator::WriteProjectFiles() { // If not an in source build, then create the output directory - if (strcmp(this->GetCurrentBinaryDirectory(), this->GetSourceDirectory()) != - 0) { + if (this->GetCurrentBinaryDirectory() != this->GetSourceDirectory()) { if (!cmSystemTools::MakeDirectory(this->GetCurrentBinaryDirectory())) { cmSystemTools::Error("Error creating directory ", this->GetCurrentBinaryDirectory()); @@ -154,15 +126,14 @@ void cmLocalVisualStudio7Generator::WriteProjectFiles() const std::vector<cmGeneratorTarget*>& tgts = this->GetGeneratorTargets(); // Create the project file for each target. - for (std::vector<cmGeneratorTarget*>::const_iterator l = tgts.begin(); - l != tgts.end(); l++) { - if ((*l)->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + for (cmGeneratorTarget* l : tgts) { + if (l->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } // INCLUDE_EXTERNAL_MSPROJECT command only affects the workspace // so don't build a projectfile for it - if (!(*l)->GetProperty("EXTERNAL_MSPROJECT")) { - this->CreateSingleVCProj((*l)->GetName().c_str(), *l); + if (!l->GetProperty("EXTERNAL_MSPROJECT")) { + this->CreateSingleVCProj(l->GetName(), l); } } } @@ -239,19 +210,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 +256,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; } } @@ -618,6 +602,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( switch (target->GetType()) { case cmStateEnums::OBJECT_LIBRARY: targetBuilds = false; // no manifest tool for object library + CM_FALLTHROUGH; case cmStateEnums::STATIC_LIBRARY: projectType = "typeStaticLibrary"; configType = "4"; @@ -633,6 +618,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( case cmStateEnums::UTILITY: case cmStateEnums::GLOBAL_TARGET: configType = "10"; + CM_FALLTHROUGH; default: targetBuilds = false; break; @@ -641,7 +627,8 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( configType = projectType; } std::string flags; - if (strcmp(configType, "10") != 0) { + std::string langForClCompile; + if (target->GetType() <= cmStateEnums::OBJECT_LIBRARY) { const std::string& linkLanguage = (this->FortranProject ? std::string("Fortran") : target->GetLinkerLanguage(configName)); @@ -651,10 +638,11 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( target->GetName().c_str()); return; } - if (linkLanguage == "C" || linkLanguage == "CXX" || - linkLanguage == "Fortran") { + langForClCompile = linkLanguage; + if (langForClCompile == "C" || langForClCompile == "CXX" || + langForClCompile == "Fortran") { std::string baseFlagVar = "CMAKE_"; - baseFlagVar += linkLanguage; + baseFlagVar += langForClCompile; baseFlagVar += "_FLAGS"; flags = this->Makefile->GetRequiredDefinition(baseFlagVar.c_str()); std::string flagVar = @@ -671,7 +659,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( } // Add the target-specific flags. - this->AddCompileOptions(flags, target, linkLanguage, configName); + this->AddCompileOptions(flags, target, langForClCompile, configName); // Check IPO related warning/error. target->IsIPOEnabled(linkLanguage, configName); @@ -702,13 +690,20 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( Options targetOptions(this, t, table, gg->ExtraFlagTable); targetOptions.FixExceptionHandlingDefault(); std::string asmLocation = configName + "/"; - targetOptions.AddFlag("AssemblerListingLocation", asmLocation.c_str()); + targetOptions.AddFlag("AssemblerListingLocation", asmLocation); targetOptions.Parse(flags.c_str()); targetOptions.Parse(defineFlags.c_str()); targetOptions.ParseFinish(); - std::vector<std::string> targetDefines; - target->GetCompileDefinitions(targetDefines, configName, "CXX"); - targetOptions.AddDefines(targetDefines); + if (!langForClCompile.empty()) { + std::vector<std::string> targetDefines; + target->GetCompileDefinitions(targetDefines, configName, langForClCompile); + targetOptions.AddDefines(targetDefines); + + std::vector<std::string> targetIncludes; + this->GetIncludeDirectories(targetIncludes, target, langForClCompile, + configName); + targetOptions.AddIncludes(targetIncludes); + } targetOptions.SetVerboseMakefile( this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE")); @@ -795,26 +790,12 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( << this->ConvertToXMLOutputPath(modDir.c_str()) << "\\$(ConfigurationName)\"\n"; } - fout << "\t\t\t\tAdditionalIncludeDirectories=\""; - std::vector<std::string> includes; - this->GetIncludeDirectories(includes, target, "C", configName); - std::vector<std::string>::iterator i = includes.begin(); - for (; i != includes.end(); ++i) { - // output the include path - std::string ipath = this->ConvertToXMLOutputPath(i->c_str()); - fout << ipath << ";"; - // if this is fortran then output the include with - // a ConfigurationName on the end of it. - if (this->FortranProject) { - ipath = i->c_str(); - ipath += "/$(ConfigurationName)"; - ipath = this->ConvertToXMLOutputPath(ipath.c_str()); - fout << ipath << ";"; - } - } - fout << "\"\n"; + targetOptions.OutputAdditionalIncludeDirectories( + fout, "\t\t\t\t", "\n", + this->FortranProject ? "Fortran" : langForClCompile); targetOptions.OutputFlagMap(fout, "\t\t\t\t"); - targetOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t", "\n", "CXX"); + targetOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t", "\n", + langForClCompile); fout << "\t\t\t\tObjectFile=\"$(IntDir)\\\"\n"; if (target->GetType() <= cmStateEnums::OBJECT_LIBRARY) { // Specify the compiler program database file if configured. @@ -831,17 +812,10 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( fout << "\t\t\t<Tool\n" "\t\t\t\tName=\"MASM\"\n" - "\t\t\t\tIncludePaths=\"" ; /* clang-format on */ - const char* sep = ""; - for (i = includes.begin(); i != includes.end(); ++i) { - std::string inc = *i; - cmConvertToWindowsSlash(inc); - fout << sep << this->EscapeForXML(inc); - sep = ";"; - } - fout << "\"\n"; + targetOptions.OutputAdditionalIncludeDirectories(fout, "\t\t\t\t", "\n", + "ASM_MASM"); // Use same preprocessor definitions as VCCLCompilerTool. targetOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t", "\n", "ASM_MASM"); @@ -861,14 +835,10 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( if (this->FortranProject) { tool = "VFResourceCompilerTool"; } - fout << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"\n" - << "\t\t\t\tAdditionalIncludeDirectories=\""; - for (i = includes.begin(); i != includes.end(); ++i) { - std::string ipath = this->ConvertToXMLOutputPath(i->c_str()); - fout << ipath << ";"; - } + fout << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"\n"; + targetOptions.OutputAdditionalIncludeDirectories(fout, "\n\t\t\t\t", "", + "RC"); // add the -D flags to the RC tool - fout << "\""; targetOptions.OutputPreprocessorDefinitions(fout, "\n\t\t\t\t", "", "RC"); fout << "/>\n"; tool = "VCMIDLTool"; @@ -876,12 +846,8 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( tool = "VFMIDLTool"; } fout << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"\n"; - fout << "\t\t\t\tAdditionalIncludeDirectories=\""; - for (i = includes.begin(); i != includes.end(); ++i) { - std::string ipath = this->ConvertToXMLOutputPath(i->c_str()); - fout << ipath << ";"; - } - fout << "\"\n"; + targetOptions.OutputAdditionalIncludeDirectories(fout, "\n\t\t\t\t", "", + "MIDL"); fout << "\t\t\t\tMkTypLibCompatible=\"false\"\n"; if (gg->GetPlatformName() == "x64") { fout << "\t\t\t\tTargetEnvironment=\"3\"\n"; @@ -1008,7 +974,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool( if (mdi && !mdi->DefFile.empty()) { std::string defFile = this->ConvertToOutputFormat(mdi->DefFile, cmOutputConverter::SHELL); - linkOptions.AddFlag("ModuleDefinitionFile", defFile.c_str()); + linkOptions.AddFlag("ModuleDefinitionFile", defFile); } switch (target->GetType()) { @@ -1368,13 +1334,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 @@ -1386,7 +1365,7 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout, // Add the file to the list of sources. std::string const source = sf->GetFullPath(); cmSourceGroup* sourceGroup = - this->Makefile->FindSourceGroup(source.c_str(), sourceGroups); + this->Makefile->FindSourceGroup(source, sourceGroups); sourceGroup->AssignSource(sf); } @@ -1400,7 +1379,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"; @@ -1416,6 +1395,7 @@ struct cmLVS7GFileConfig std::string CompileDefs; std::string CompileDefsConfig; std::string AdditionalDeps; + std::string IncludeDirs; bool ExcludedFromBuild; }; @@ -1446,15 +1426,34 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo( i != configs.end(); ++i, ++ci) { std::string configUpper = cmSystemTools::UpperCase(*i); cmLVS7GFileConfig fc; + + std::string lang = + lg->GlobalGenerator->GetLanguageFromExtension(sf.GetExtension().c_str()); + const std::string& sourceLang = lg->GetSourceFileLanguage(sf); + bool needForceLang = false; + // source file does not match its extension language + if (lang != sourceLang) { + needForceLang = true; + lang = sourceLang; + } + + cmGeneratorExpressionInterpreter genexInterpreter(lg, gt, *i, + gt->GetName(), lang); + bool needfc = false; if (!objectName.empty()) { fc.ObjectName = objectName; needfc = true; } - if (const char* cflags = sf.GetProperty("COMPILE_FLAGS")) { - cmGeneratorExpression ge; - std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(cflags); - fc.CompileFlags = cge->Evaluate(lg, *i, false, gt); + const std::string COMPILE_FLAGS("COMPILE_FLAGS"); + if (const char* cflags = sf.GetProperty(COMPILE_FLAGS)) { + fc.CompileFlags = genexInterpreter.Evaluate(cflags, COMPILE_FLAGS); + needfc = true; + } + const std::string COMPILE_OPTIONS("COMPILE_OPTIONS"); + if (const char* coptions = sf.GetProperty(COMPILE_OPTIONS)) { + lg->AppendCompileOptions( + fc.CompileFlags, genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS)); needfc = true; } if (lg->FortranProject) { @@ -1472,14 +1471,22 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo( break; } } - if (const char* cdefs = sf.GetProperty("COMPILE_DEFINITIONS")) { - fc.CompileDefs = cdefs; + const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS"); + if (const char* cdefs = sf.GetProperty(COMPILE_DEFINITIONS)) { + fc.CompileDefs = genexInterpreter.Evaluate(cdefs, COMPILE_DEFINITIONS); needfc = true; } std::string defPropName = "COMPILE_DEFINITIONS_"; defPropName += configUpper; - if (const char* ccdefs = sf.GetProperty(defPropName.c_str())) { - fc.CompileDefsConfig = ccdefs; + if (const char* ccdefs = sf.GetProperty(defPropName)) { + fc.CompileDefsConfig = + genexInterpreter.Evaluate(ccdefs, COMPILE_DEFINITIONS); + needfc = true; + } + + const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES"); + if (const char* cincs = sf.GetProperty(INCLUDE_DIRECTORIES)) { + fc.IncludeDirs = genexInterpreter.Evaluate(cincs, INCLUDE_DIRECTORIES); needfc = true; } @@ -1497,16 +1504,7 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo( } } - std::string lang = - lg->GlobalGenerator->GetLanguageFromExtension(sf.GetExtension().c_str()); - const std::string& sourceLang = lg->GetSourceFileLanguage(sf); const std::string& linkLanguage = gt->GetLinkerLanguage(i->c_str()); - bool needForceLang = false; - // source file does not match its extension language - if (lang != sourceLang) { - needForceLang = true; - lang = sourceLang; - } // If HEADER_FILE_ONLY is set, we must suppress this generation in // the project file fc.ExcludedFromBuild = sf.GetPropertyAsBool("HEADER_FILE_ONLY") || @@ -1567,7 +1565,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 +1577,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 +1588,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 +1603,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); @@ -1624,7 +1620,7 @@ bool cmLocalVisualStudio7Generator::WriteGroup( this->WriteCustomRule(fout, configs, source.c_str(), *command, fcinfo); } else if (!fcinfo.FileConfigMap.empty()) { const char* aCompilerTool = "VCCLCompilerTool"; - const char* ppLang = "CXX"; + std::string ppLang = "CXX"; if (this->FortranProject) { aCompilerTool = "VFFortranCompilerTool"; } @@ -1671,7 +1667,7 @@ bool cmLocalVisualStudio7Generator::WriteGroup( fout << "\t\t\t\t\t<Tool\n" << "\t\t\t\t\tName=\"" << aCompilerTool << "\"\n"; if (!fc.CompileFlags.empty() || !fc.CompileDefs.empty() || - !fc.CompileDefsConfig.empty()) { + !fc.CompileDefsConfig.empty() || !fc.IncludeDirs.empty()) { Options::Tool tool = Options::Compiler; cmVS7FlagTable const* table = cmLocalVisualStudio7GeneratorFlagTable; @@ -1683,7 +1679,14 @@ bool cmLocalVisualStudio7Generator::WriteGroup( fileOptions.Parse(fc.CompileFlags.c_str()); fileOptions.AddDefines(fc.CompileDefs.c_str()); fileOptions.AddDefines(fc.CompileDefsConfig.c_str()); + // validate source level include directories + std::vector<std::string> includes; + this->AppendIncludeDirectories(includes, fc.IncludeDirs, **sf); + fileOptions.AddIncludes(includes); fileOptions.OutputFlagMap(fout, "\t\t\t\t\t"); + fileOptions.OutputAdditionalIncludeDirectories( + fout, "\t\t\t\t\t", "\n", + ppLang == "CXX" && this->FortranProject ? "Fortran" : ppLang); fileOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t\t", "\n", ppLang); } diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h index 7a77574..02e6931 100644 --- a/Source/cmLocalVisualStudio7Generator.h +++ b/Source/cmLocalVisualStudio7Generator.h @@ -35,12 +35,12 @@ public: virtual ~cmLocalVisualStudio7Generator(); - virtual void AddHelperCommands(); + void AddHelperCommands() override; /** * Generate the makefile for this directory. */ - virtual void Generate(); + void Generate() override; enum BuildType { @@ -56,16 +56,15 @@ public: */ void SetBuildType(BuildType, const std::string& name); - virtual std::string GetTargetDirectory( - cmGeneratorTarget const* target) const; + std::string GetTargetDirectory( + cmGeneratorTarget const* target) const override; cmSourceFile* CreateVCProjBuildRule(); void WriteStampFiles(); - virtual std::string ComputeLongestObjectDirectory( - cmGeneratorTarget const*) const; + std::string ComputeLongestObjectDirectory( + cmGeneratorTarget const*) const override; 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.cxx b/Source/cmLocalVisualStudioGenerator.cxx index bbb91e0..2237da7 100644 --- a/Source/cmLocalVisualStudioGenerator.cxx +++ b/Source/cmLocalVisualStudioGenerator.cxx @@ -39,10 +39,8 @@ void cmLocalVisualStudioGenerator::ComputeObjectFilenames( // windows file names are not case sensitive. std::map<std::string, int> counts; - for (std::map<cmSourceFile const*, std::string>::iterator si = - mapping.begin(); - si != mapping.end(); ++si) { - cmSourceFile const* sf = si->first; + for (auto const& si : mapping) { + cmSourceFile const* sf = si.first; std::string objectNameLower = cmSystemTools::LowerCase( cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath())); if (custom_ext) { @@ -57,10 +55,8 @@ void cmLocalVisualStudioGenerator::ComputeObjectFilenames( // For all source files producing duplicate names we need unique // object name computation. - for (std::map<cmSourceFile const*, std::string>::iterator si = - mapping.begin(); - si != mapping.end(); ++si) { - cmSourceFile const* sf = si->first; + for (auto& si : mapping) { + cmSourceFile const* sf = si.first; std::string objectName = cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath()); if (custom_ext) { @@ -74,7 +70,7 @@ void cmLocalVisualStudioGenerator::ComputeObjectFilenames( objectName = this->GetObjectFileNameWithoutTarget( *sf, dir_max, &keptSourceExtension, custom_ext); } - si->second = objectName; + si.second = objectName; } } diff --git a/Source/cmLocalVisualStudioGenerator.h b/Source/cmLocalVisualStudioGenerator.h index cba24fe..3fdafd2 100644 --- a/Source/cmLocalVisualStudioGenerator.h +++ b/Source/cmLocalVisualStudioGenerator.h @@ -44,11 +44,9 @@ public: virtual std::string ComputeLongestObjectDirectory( cmGeneratorTarget const*) const = 0; - virtual void AddCMakeListsRules() = 0; - - virtual void ComputeObjectFilenames( + void ComputeObjectFilenames( std::map<cmSourceFile const*, std::string>& mapping, - cmGeneratorTarget const* = 0); + cmGeneratorTarget const* = 0) override; protected: virtual const char* ReportErrorLabel() const; diff --git a/Source/cmLocalXCodeGenerator.cxx b/Source/cmLocalXCodeGenerator.cxx index 853e66c..92c958d 100644 --- a/Source/cmLocalXCodeGenerator.cxx +++ b/Source/cmLocalXCodeGenerator.cxx @@ -31,10 +31,10 @@ std::string cmLocalXCodeGenerator::GetTargetDirectory( } void cmLocalXCodeGenerator::AppendFlagEscape(std::string& flags, - const std::string& rawFlag) + const std::string& rawFlag) const { - cmGlobalXCodeGenerator* gg = - static_cast<cmGlobalXCodeGenerator*>(this->GlobalGenerator); + const cmGlobalXCodeGenerator* gg = + static_cast<const cmGlobalXCodeGenerator*>(this->GlobalGenerator); gg->AppendFlag(flags, rawFlag); } @@ -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/cmLocalXCodeGenerator.h b/Source/cmLocalXCodeGenerator.h index 8c9596f..5c22dcf 100644 --- a/Source/cmLocalXCodeGenerator.h +++ b/Source/cmLocalXCodeGenerator.h @@ -31,7 +31,7 @@ public: std::string GetTargetDirectory( cmGeneratorTarget const* target) const override; void AppendFlagEscape(std::string& flags, - const std::string& rawFlag) override; + const std::string& rawFlag) const override; void Generate() override; virtual void GenerateInstallRules(); void ComputeObjectFilenames( diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx index 74a1da0..07943e3 100644 --- a/Source/cmMacroCommand.cxx +++ b/Source/cmMacroCommand.cxx @@ -4,6 +4,7 @@ #include <sstream> #include <stdio.h> +#include <utility> #include "cmAlgorithms.h" #include "cmExecutionStatus.h" @@ -131,7 +132,7 @@ bool cmMacroHelperCommand::InvokeInitialPass( } arg.Delim = k.Delim; arg.Line = k.Line; - newLFF.Arguments.push_back(arg); + newLFF.Arguments.push_back(std::move(arg)); } cmExecutionStatus status; if (!this->Makefile->ExecuteCommand(newLFF, status) || diff --git a/Source/cmMakeDirectoryCommand.cxx b/Source/cmMakeDirectoryCommand.cxx index 06e295b..aff4ca6 100644 --- a/Source/cmMakeDirectoryCommand.cxx +++ b/Source/cmMakeDirectoryCommand.cxx @@ -15,13 +15,13 @@ bool cmMakeDirectoryCommand::InitialPass(std::vector<std::string> const& args, this->SetError("called with incorrect number of arguments"); return false; } - if (!this->Makefile->CanIWriteThisFile(args[0].c_str())) { + if (!this->Makefile->CanIWriteThisFile(args[0])) { std::string e = "attempted to create a directory: " + args[0] + " into a source directory."; this->SetError(e); cmSystemTools::SetFatalErrorOccured(); return false; } - cmSystemTools::MakeDirectory(args[0].c_str()); + cmSystemTools::MakeDirectory(args[0]); return true; } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 5643c97..b468208 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> @@ -19,7 +20,7 @@ #include "cmCustomCommand.h" #include "cmCustomCommandLines.h" #include "cmExecutionStatus.h" -#include "cmExpandedCommandArgument.h" +#include "cmExpandedCommandArgument.h" // IWYU pragma: keep #include "cmFileLockPool.h" #include "cmFunctionBlocker.h" #include "cmGeneratorExpression.h" @@ -94,8 +95,7 @@ cmMakefile::cmMakefile(cmGlobalGenerator* globalGenerator, this->AddSourceGroup("Object Files", "\\.(lo|o|obj)$"); this->ObjectLibrariesSourceGroupIndex = this->SourceGroups.size(); - this->SourceGroups.push_back( - cmSourceGroup("Object Libraries", "^MATCH_NO_SOURCES$")); + this->SourceGroups.emplace_back("Object Libraries", "^MATCH_NO_SOURCES$"); #endif } @@ -122,6 +122,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 +598,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); @@ -627,7 +663,7 @@ struct file_not_persistent bool operator()(const std::string& path) const { return !(path.find("CMakeTmp") == std::string::npos && - cmSystemTools::FileExists(path.c_str())); + cmSystemTools::FileExists(path)); } }; } @@ -718,8 +754,9 @@ void cmMakefile::AddCustomCommandToTarget( return; } + cmTarget& t = ti->second; if (objLibraryCommands == RejectObjectLibraryCommands && - ti->second.GetType() == cmStateEnums::OBJECT_LIBRARY) { + t.GetType() == cmStateEnums::OBJECT_LIBRARY) { std::ostringstream e; e << "Target \"" << target << "\" is an OBJECT library " @@ -727,7 +764,7 @@ void cmMakefile::AddCustomCommandToTarget( this->IssueMessage(cmake::FATAL_ERROR, e.str()); return; } - if (ti->second.GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (t.GetType() == cmStateEnums::INTERFACE_LIBRARY) { std::ostringstream e; e << "Target \"" << target << "\" is an INTERFACE library " @@ -754,13 +791,13 @@ void cmMakefile::AddCustomCommandToTarget( cc.SetDepfile(depfile); switch (type) { case cmTarget::PRE_BUILD: - ti->second.AddPreBuildCommand(cc); + t.AddPreBuildCommand(cc); break; case cmTarget::PRE_LINK: - ti->second.AddPreLinkCommand(cc); + t.AddPreLinkCommand(cc); break; case cmTarget::POST_BUILD: - ti->second.AddPostBuildCommand(cc); + t.AddPostBuildCommand(cc); break; } } @@ -818,7 +855,7 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput( std::string outName = gg->GenerateRuleFile(outputs[0]); // Check if the rule file already exists. - file = this->GetSource(outName); + file = this->GetSource(outName, cmSourceFileLocationKind::Known); if (file && file->GetCustomCommand() && !replace) { // The rule file already exists. if (commandLines != file->GetCustomCommand()->GetCommandLines()) { @@ -831,19 +868,22 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput( // Create a cmSourceFile for the rule file. if (!file) { - file = this->CreateSource(outName, true); + file = + this->CreateSource(outName, true, cmSourceFileLocationKind::Known); } file->SetProperty("__CMAKE_RULE", "1"); } // Always create the output sources and mark them generated. for (std::string const& o : outputs) { - if (cmSourceFile* out = this->GetOrCreateSource(o, true)) { + if (cmSourceFile* out = + this->GetOrCreateSource(o, true, cmSourceFileLocationKind::Known)) { out->SetProperty("GENERATED", "1"); } } for (std::string const& o : byproducts) { - if (cmSourceFile* out = this->GetOrCreateSource(o, true)) { + if (cmSourceFile* out = + this->GetOrCreateSource(o, true, cmSourceFileLocationKind::Known)) { out->SetProperty("GENERATED", "1"); } } @@ -930,7 +970,7 @@ void cmMakefile::AddCustomCommandOldStyle( } // Each output must get its own copy of this rule. - cmsys::RegularExpression sourceFiles("\\.(C|M|c|c\\+\\+|cc|cpp|cxx|m|mm|" + cmsys::RegularExpression sourceFiles("\\.(C|M|c|c\\+\\+|cc|cpp|cxx|cu|m|mm|" "rc|def|r|odl|idl|hpj|bat|h|h\\+\\+|" "hm|hpp|hxx|in|txx|inl)$"); for (std::string const& oi : outputs) { @@ -970,7 +1010,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) @@ -991,28 +1031,28 @@ cmTarget* cmMakefile::AddUtilityCommand( commandLine.push_back(arg4); } cmCustomCommandLines commandLines; - commandLines.push_back(commandLine); + commandLines.push_back(std::move(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 +1060,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"); } @@ -1054,7 +1095,8 @@ cmTarget* cmMakefile::AddUtilityCommand( // Always create the byproduct sources and mark them generated. for (std::string const& byproduct : byproducts) { - if (cmSourceFile* out = this->GetOrCreateSource(byproduct, true)) { + if (cmSourceFile* out = this->GetOrCreateSource( + byproduct, true, cmSourceFileLocationKind::Known)) { out->SetProperty("GENERATED", "1"); } } @@ -1062,9 +1104,9 @@ cmTarget* cmMakefile::AddUtilityCommand( return target; } -void cmMakefile::AddDefineFlag(const char* flag) +void cmMakefile::AddDefineFlag(std::string const& flag) { - if (!flag) { + if (flag.empty()) { return; } @@ -1080,7 +1122,7 @@ void cmMakefile::AddDefineFlag(const char* flag) this->AddDefineFlag(flag, this->DefineFlags); } -void cmMakefile::AddDefineFlag(const char* flag, std::string& dflags) +void cmMakefile::AddDefineFlag(std::string const& flag, std::string& dflags) { // remove any \n\r std::string::size_type initSize = dflags.size(); @@ -1090,14 +1132,13 @@ void cmMakefile::AddDefineFlag(const char* flag, std::string& dflags) std::replace(flagStart, dflags.end(), '\r', ' '); } -void cmMakefile::RemoveDefineFlag(const char* flag) +void cmMakefile::RemoveDefineFlag(std::string const& flag) { // Check the length of the flag to remove. - std::string::size_type len = strlen(flag); - if (len < 1) { + if (flag.empty()) { return; } - + std::string::size_type const len = flag.length(); // Update the string used for the old DEFINITIONS property. this->RemoveDefineFlag(flag, len, this->DefineFlagsOrig); @@ -1110,7 +1151,8 @@ void cmMakefile::RemoveDefineFlag(const char* flag) this->RemoveDefineFlag(flag, len, this->DefineFlags); } -void cmMakefile::RemoveDefineFlag(const char* flag, std::string::size_type len, +void cmMakefile::RemoveDefineFlag(std::string const& flag, + std::string::size_type len, std::string& dflags) { // Remove all instances of the flag that are surrounded by @@ -1127,9 +1169,9 @@ void cmMakefile::RemoveDefineFlag(const char* flag, std::string::size_type len, } } -void cmMakefile::AddCompileOption(const char* option) +void cmMakefile::AddCompileOption(std::string const& option) { - this->AppendProperty("COMPILE_OPTIONS", option); + this->AppendProperty("COMPILE_OPTIONS", option.c_str()); } bool cmMakefile::ParseDefineFlag(std::string const& def, bool remove) @@ -1138,14 +1180,14 @@ bool cmMakefile::ParseDefineFlag(std::string const& def, bool remove) static cmsys::RegularExpression valid("^[-/]D[A-Za-z_][A-Za-z0-9_]*(=.*)?$"); // Make sure the definition matches. - if (!valid.find(def.c_str())) { + if (!valid.find(def)) { return false; } // Definitions with non-trivial values require a policy check. static cmsys::RegularExpression trivial( "^[-/]D[A-Za-z_][A-Za-z0-9_]*(=[A-Za-z0-9_.]+)?$"); - if (!trivial.find(def.c_str())) { + if (!trivial.find(def)) { // This definition has a non-trivial value. switch (this->GetPolicyStatus(cmPolicies::CMP0005)) { case cmPolicies::WARN: @@ -1367,9 +1409,9 @@ void cmMakefile::Configure() // make sure the CMakeFiles dir is there std::string filesDir = this->StateSnapshot.GetDirectory().GetCurrentBinary(); filesDir += cmake::GetCMakeFilesDirectory(); - cmSystemTools::MakeDirectory(filesDir.c_str()); + cmSystemTools::MakeDirectory(filesDir); - assert(cmSystemTools::FileExists(currentStart.c_str(), true)); + assert(cmSystemTools::FileExists(currentStart, true)); this->AddDefinition("CMAKE_PARENT_LIST_FILE", currentStart.c_str()); cmListFile listFile; @@ -1437,8 +1479,8 @@ void cmMakefile::Configure() if (!hasProject) { cmListFileFunction project; project.Name = "PROJECT"; - cmListFileArgument prj("Project", cmListFileArgument::Unquoted, 0); - project.Arguments.push_back(prj); + project.Arguments.emplace_back("Project", cmListFileArgument::Unquoted, + 0); listFile.Functions.insert(listFile.Functions.begin(), project); } } @@ -1530,7 +1572,7 @@ void cmMakefile::AddSubDirectory(const std::string& srcPath, newSnapshot.GetDirectory().SetCurrentSource(srcPath); newSnapshot.GetDirectory().SetCurrentBinary(binPath); - cmSystemTools::MakeDirectory(binPath.c_str()); + cmSystemTools::MakeDirectory(binPath); cmMakefile* subMf = new cmMakefile(this->GlobalGenerator, newSnapshot); this->GetGlobalGenerator()->AddMakefile(subMf); @@ -1834,7 +1876,7 @@ cmTarget* cmMakefile::AddLibrary(const std::string& lname, return target; } -cmTarget* cmMakefile::AddExecutable(const char* exeName, +cmTarget* cmMakefile::AddExecutable(const std::string& exeName, const std::vector<std::string>& srcs, bool excludeFromAll) { @@ -1894,7 +1936,7 @@ cmSourceFile* cmMakefile::GetSourceFileWithOutput( { // If the queried path is not absolute we use the backward compatible // linear-time search for an output with a matching suffix. - if (!cmSystemTools::FileIsFullPath(name.c_str())) { + if (!cmSystemTools::FileIsFullPath(name)) { return this->LinearGetSourceFileWithOutput(name); } // Otherwise we use an efficient lookup map. @@ -1913,7 +1955,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; @@ -1923,7 +1965,7 @@ cmSourceGroup* cmMakefile::GetSourceGroup( if (sg != nullptr) { // iterate through its children to find match source group for (unsigned int i = 1; i < name.size(); ++i) { - sg = sg->LookupChild(name[i].c_str()); + sg = sg->LookupChild(name[i]); if (sg == nullptr) { break; } @@ -1967,7 +2009,7 @@ void cmMakefile::AddSourceGroup(const std::vector<std::string>& name, if (i == -1) { // group does not exist nor belong to any existing group // add its first component - this->SourceGroups.push_back(cmSourceGroup(name[0].c_str(), regex)); + this->SourceGroups.push_back(cmSourceGroup(name[0], regex)); sg = this->GetSourceGroup(currentName); i = 0; // last component found } @@ -1977,8 +2019,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 = sg->LookupChild(name[i].c_str()); + sg->AddChild(cmSourceGroup(name[i], nullptr, sg->GetFullName().c_str())); + sg = sg->LookupChild(name[i]); } sg->SetGroupRegex(regex); @@ -2013,7 +2055,7 @@ cmSourceGroup* cmMakefile::GetOrCreateSourceGroup(const std::string& name) * inherited ones. */ cmSourceGroup* cmMakefile::FindSourceGroup( - const char* source, std::vector<cmSourceGroup>& groups) const + const std::string& source, std::vector<cmSourceGroup>& groups) const { // First search for a group that lists the file explicitly. for (std::vector<cmSourceGroup>::reverse_iterator sg = groups.rbegin(); @@ -2205,25 +2247,38 @@ bool cmMakefile::PlatformIsx32() const return false; } -bool cmMakefile::PlatformIsAppleIos() const +cmMakefile::AppleSDK cmMakefile::GetAppleSDKType() const { std::string sdkRoot; sdkRoot = this->GetSafeDefinition("CMAKE_OSX_SYSROOT"); sdkRoot = cmSystemTools::LowerCase(sdkRoot); - const std::string embedded[] = { - "appletvos", "appletvsimulator", "iphoneos", - "iphonesimulator", "watchos", "watchsimulator", + struct + { + std::string name; + AppleSDK sdk; + } const sdkDatabase[]{ + { "appletvos", AppleSDK::AppleTVOS }, + { "appletvsimulator", AppleSDK::AppleTVSimulator }, + { "iphoneos", AppleSDK::IPhoneOS }, + { "iphonesimulator", AppleSDK::IPhoneSimulator }, + { "watchos", AppleSDK::WatchOS }, + { "watchsimulator", AppleSDK::WatchSimulator }, }; - for (std::string const& i : embedded) { - if (sdkRoot.find(i) == 0 || - sdkRoot.find(std::string("/") + i) != std::string::npos) { - return true; + for (auto entry : sdkDatabase) { + if (sdkRoot.find(entry.name) == 0 || + sdkRoot.find(std::string("/") + entry.name) != std::string::npos) { + return entry.sdk; } } - return false; + return AppleSDK::MacOS; +} + +bool cmMakefile::PlatformIsAppleEmbedded() const +{ + return GetAppleSDKType() != AppleSDK::MacOS; } const char* cmMakefile::GetSONameFlag(const std::string& language) const @@ -2237,7 +2292,7 @@ const char* cmMakefile::GetSONameFlag(const std::string& language) const return GetDefinition(name); } -bool cmMakefile::CanIWriteThisFile(const char* fileName) const +bool cmMakefile::CanIWriteThisFile(std::string const& fileName) const { if (!this->IsOn("CMAKE_DISABLE_SOURCE_CHANGES")) { return true; @@ -2977,7 +3032,7 @@ bool cmMakefile::ExpandArguments( for (cmListFileArgument const& i : inArgs) { // No expansion in a bracket argument. if (i.Delim == cmListFileArgument::Bracket) { - outArgs.push_back(cmExpandedCommandArgument(i.Value, true)); + outArgs.emplace_back(i.Value, true); continue; } // Expand the variables in the argument. @@ -2988,12 +3043,12 @@ bool cmMakefile::ExpandArguments( // If the argument is quoted, it should be one argument. // Otherwise, it may be a list of arguments. if (i.Delim == cmListFileArgument::Quoted) { - outArgs.push_back(cmExpandedCommandArgument(value, true)); + outArgs.emplace_back(value, true); } else { std::vector<std::string> stringArgs; cmSystemTools::ExpandListArgument(value, stringArgs); for (std::string const& stringArg : stringArgs) { - outArgs.push_back(cmExpandedCommandArgument(stringArg, false)); + outArgs.emplace_back(stringArg, false); } } } @@ -3050,19 +3105,19 @@ std::unique_ptr<cmFunctionBlocker> cmMakefile::RemoveFunctionBlocker( return std::unique_ptr<cmFunctionBlocker>(); } -const char* cmMakefile::GetHomeDirectory() const +std::string const& cmMakefile::GetHomeDirectory() const { return this->GetCMakeInstance()->GetHomeDirectory(); } -const char* cmMakefile::GetHomeOutputDirectory() const +std::string const& cmMakefile::GetHomeOutputDirectory() const { return this->GetCMakeInstance()->GetHomeOutputDirectory(); } -void cmMakefile::SetScriptModeFile(const char* scriptfile) +void cmMakefile::SetScriptModeFile(std::string const& scriptfile) { - this->AddDefinition("CMAKE_SCRIPT_MODE_FILE", scriptfile); + this->AddDefinition("CMAKE_SCRIPT_MODE_FILE", scriptfile.c_str()); } void cmMakefile::SetArgcArgv(const std::vector<std::string>& args) @@ -3080,35 +3135,53 @@ void cmMakefile::SetArgcArgv(const std::vector<std::string>& args) } } -cmSourceFile* cmMakefile::GetSource(const std::string& sourceName) const +cmSourceFile* cmMakefile::GetSource(const std::string& sourceName, + cmSourceFileLocationKind kind) const { - cmSourceFileLocation sfl(this, sourceName); - for (cmSourceFile* sf : this->SourceFiles) { - if (sf->Matches(sfl)) { - return sf; + cmSourceFileLocation sfl(this, sourceName, kind); + 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; } cmSourceFile* cmMakefile::CreateSource(const std::string& sourceName, - bool generated) + bool generated, + cmSourceFileLocationKind kind) { - cmSourceFile* sf = new cmSourceFile(this, sourceName); + cmSourceFile* sf = new cmSourceFile(this, sourceName, kind); if (generated) { 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; } cmSourceFile* cmMakefile::GetOrCreateSource(const std::string& sourceName, - bool generated) + bool generated, + cmSourceFileLocationKind kind) { - if (cmSourceFile* esf = this->GetSource(sourceName)) { + if (cmSourceFile* esf = this->GetSource(sourceName, kind)) { return esf; } - return this->CreateSource(sourceName, generated); + return this->CreateSource(sourceName, generated, kind); } void cmMakefile::AddTargetObject(std::string const& tgtName, @@ -3159,7 +3232,7 @@ int cmMakefile::TryCompile(const std::string& srcdir, this->IsSourceFileTryCompile = fast; // does the binary directory exist ? If not create it... if (!cmSystemTools::FileIsDirectory(bindir)) { - cmSystemTools::MakeDirectory(bindir.c_str()); + cmSystemTools::MakeDirectory(bindir); } // change to the tests directory and run cmake @@ -3186,6 +3259,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(); @@ -3336,7 +3410,7 @@ std::string cmMakefile::GetModulesFile(const char* filename) const cmSystemTools::ConvertToUnixSlashes(itempl); itempl += "/"; itempl += filename; - if (cmSystemTools::FileExists(itempl.c_str())) { + if (cmSystemTools::FileExists(itempl)) { moduleInCMakeModulePath = itempl; break; } @@ -3348,7 +3422,7 @@ std::string cmMakefile::GetModulesFile(const char* filename) const moduleInCMakeRoot += "/Modules/"; moduleInCMakeRoot += filename; cmSystemTools::ConvertToUnixSlashes(moduleInCMakeRoot); - if (!cmSystemTools::FileExists(moduleInCMakeRoot.c_str())) { + if (!cmSystemTools::FileExists(moduleInCMakeRoot)) { moduleInCMakeRoot.clear(); } @@ -3480,11 +3554,11 @@ int cmMakefile::ConfigureFile(const char* infile, const char* outfile, this->AddCMakeOutputFile(soutfile); mode_t perm = 0; - cmSystemTools::GetPermissions(sinfile.c_str(), perm); + cmSystemTools::GetPermissions(sinfile, perm); std::string::size_type pos = soutfile.rfind('/'); if (pos != std::string::npos) { std::string path = soutfile.substr(0, pos); - cmSystemTools::MakeDirectory(path.c_str()); + cmSystemTools::MakeDirectory(path); } if (copyonly) { @@ -3544,7 +3618,7 @@ int cmMakefile::ConfigureFile(const char* infile, const char* outfile, soutfile.c_str())) { res = 0; } else { - cmSystemTools::SetPermissions(soutfile.c_str(), perm); + cmSystemTools::SetPermissions(soutfile, perm); } cmSystemTools::RemoveFile(tempOutputFile); } @@ -3616,6 +3690,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; @@ -3623,7 +3707,7 @@ void cmMakefile::AddCMakeDependFilesFromUser() cmSystemTools::ExpandListArgument(deps_str, deps); } for (std::string const& dep : deps) { - if (cmSystemTools::FileIsFullPath(dep.c_str())) { + if (cmSystemTools::FileIsFullPath(dep)) { this->AddCMakeDependFile(dep); } else { std::string f = this->GetCurrentSourceDirectory(); @@ -3980,7 +4064,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 +4217,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 +4314,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 +4335,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 +4345,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 +4373,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 +4398,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 +4420,10 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, existingCxxStandard = defaultCxxStandard; } - if (std::find_if(cmArrayBegin(CXX_STANDARDS), cmArrayEnd(CXX_STANDARDS), - cmStrCmp(existingCxxStandard)) == - cmArrayEnd(CXX_STANDARDS)) { + const char* const* existingCxxLevel = + std::find_if(cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS), + cmStrCmp(existingCxxStandard)); + if (existingCxxLevel == cm::cend(CXX_STANDARDS)) { std::ostringstream e; e << "The CXX_STANDARD property on target \"" << target->GetName() << "\" contained an invalid value: \"" << existingCxxStandard << "\"."; @@ -4347,36 +4431,16 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, return false; } - const char* const* existingCxxIt = existingCxxStandard - ? std::find_if(cmArrayBegin(CXX_STANDARDS), cmArrayEnd(CXX_STANDARDS), - cmStrCmp(existingCxxStandard)) - : cmArrayEnd(CXX_STANDARDS); + /* clang-format off */ + const char* const* needCxxLevel = + needCxx17 ? &CXX_STANDARDS[3] + : needCxx14 ? &CXX_STANDARDS[2] + : needCxx11 ? &CXX_STANDARDS[1] + : needCxx98 ? &CXX_STANDARDS[0] + : nullptr; + /* clang-format on */ - if (needCxx17 && - existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS), - cmArrayEnd(CXX_STANDARDS), - cmStrCmp("17"))) { - return false; - } - if (needCxx14 && - existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS), - cmArrayEnd(CXX_STANDARDS), - cmStrCmp("14"))) { - return false; - } - if (needCxx11 && - existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS), - cmArrayEnd(CXX_STANDARDS), - cmStrCmp("11"))) { - return false; - } - if (needCxx98 && - existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS), - cmArrayEnd(CXX_STANDARDS), - cmStrCmp("98"))) { - return false; - } - return true; + return !needCxxLevel || needCxxLevel <= existingCxxLevel; } void cmMakefile::CheckNeededCxxLanguage(const std::string& feature, @@ -4422,10 +4486,12 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, needCxx17); const char* existingCxxStandard = target->GetProperty("CXX_STANDARD"); + const char* const* existingCxxLevel = nullptr; if (existingCxxStandard) { - if (std::find_if(cmArrayBegin(CXX_STANDARDS), cmArrayEnd(CXX_STANDARDS), - cmStrCmp(existingCxxStandard)) == - cmArrayEnd(CXX_STANDARDS)) { + existingCxxLevel = + std::find_if(cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS), + cmStrCmp(existingCxxStandard)); + if (existingCxxLevel == cm::cend(CXX_STANDARDS)) { std::ostringstream e; e << "The CXX_STANDARD property on target \"" << target->GetName() << "\" contained an invalid value: \"" << existingCxxStandard << "\"."; @@ -4438,51 +4504,51 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, return false; } } - const char* const* existingCxxIt = existingCxxStandard - ? std::find_if(cmArrayBegin(CXX_STANDARDS), cmArrayEnd(CXX_STANDARDS), - cmStrCmp(existingCxxStandard)) - : cmArrayEnd(CXX_STANDARDS); - - bool setCxx98 = needCxx98 && !existingCxxStandard; - bool setCxx11 = needCxx11 && !existingCxxStandard; - bool setCxx14 = needCxx14 && !existingCxxStandard; - bool setCxx17 = needCxx17 && !existingCxxStandard; - - if (needCxx17 && existingCxxStandard && - existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS), - cmArrayEnd(CXX_STANDARDS), - cmStrCmp("17"))) { - setCxx17 = true; - } else if (needCxx14 && existingCxxStandard && - existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS), - cmArrayEnd(CXX_STANDARDS), - cmStrCmp("14"))) { - setCxx14 = true; - } else if (needCxx11 && existingCxxStandard && - existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS), - cmArrayEnd(CXX_STANDARDS), - cmStrCmp("11"))) { - setCxx11 = true; - } else if (needCxx98 && existingCxxStandard && - existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS), - cmArrayEnd(CXX_STANDARDS), - cmStrCmp("98"))) { - setCxx98 = true; - } - - if (setCxx17) { - target->SetProperty("CXX_STANDARD", "17"); - target->SetProperty("CUDA_STANDARD", "17"); - } else if (setCxx14) { - target->SetProperty("CXX_STANDARD", "14"); - target->SetProperty("CUDA_STANDARD", "14"); - } else if (setCxx11) { - target->SetProperty("CXX_STANDARD", "11"); - target->SetProperty("CUDA_STANDARD", "11"); - } else if (setCxx98) { - target->SetProperty("CXX_STANDARD", "98"); - target->SetProperty("CUDA_STANDARD", "98"); + + const char* existingCudaStandard = target->GetProperty("CUDA_STANDARD"); + const char* const* existingCudaLevel = nullptr; + if (existingCudaStandard) { + existingCudaLevel = + std::find_if(cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS), + cmStrCmp(existingCudaStandard)); + if (existingCudaLevel == cm::cend(CXX_STANDARDS)) { + std::ostringstream e; + e << "The CUDA_STANDARD property on target \"" << target->GetName() + << "\" contained an invalid value: \"" << existingCudaStandard + << "\"."; + if (error) { + *error = e.str(); + } else { + this->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.str(), + this->Backtrace); + } + return false; + } + } + + /* clang-format off */ + const char* const* needCxxLevel = + needCxx17 ? &CXX_STANDARDS[3] + : needCxx14 ? &CXX_STANDARDS[2] + : needCxx11 ? &CXX_STANDARDS[1] + : needCxx98 ? &CXX_STANDARDS[0] + : nullptr; + /* clang-format on */ + + if (needCxxLevel) { + // Ensure the C++ language level is high enough to support + // the needed C++ features. + if (!existingCxxLevel || existingCxxLevel < needCxxLevel) { + target->SetProperty("CXX_STANDARD", *needCxxLevel); + } + + // Ensure the CUDA language level is high enough to support + // the needed C++ features. + if (!existingCudaLevel || existingCudaLevel < needCxxLevel) { + target->SetProperty("CUDA_STANDARD", *needCxxLevel); + } } + return true; } @@ -4522,8 +4588,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 +4603,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..5a30790 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -20,6 +20,7 @@ #include "cmListFileCache.h" #include "cmNewLineStyle.h" #include "cmPolicies.h" +#include "cmSourceFileLocationKind.h" #include "cmStateSnapshot.h" #include "cmStateTypes.h" #include "cmTarget.h" @@ -165,9 +166,9 @@ public: /** * Add a define flag to the build. */ - void AddDefineFlag(const char* definition); - void RemoveDefineFlag(const char* definition); - void AddCompileOption(const char* option); + void AddDefineFlag(std::string const& definition); + void RemoveDefineFlag(std::string const& definition); + void AddCompileOption(std::string const& option); /** Create a new imported target with the name and type given. */ cmTarget* AddImportedTarget(const std::string& name, @@ -179,16 +180,23 @@ public: /** * Add an executable to the build. */ - cmTarget* AddExecutable(const char* exename, + cmTarget* AddExecutable(const std::string& exename, 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 + * Add a utility to the build. A utility 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 +204,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, @@ -301,13 +309,13 @@ public: bool IgnoreErrorsCMP0061() const; - const char* GetHomeDirectory() const; - const char* GetHomeOutputDirectory() const; + std::string const& GetHomeDirectory() const; + std::string const& GetHomeOutputDirectory() const; /** * Set CMAKE_SCRIPT_MODE_FILE variable when running a -P script. */ - void SetScriptModeFile(const char* scriptfile); + void SetScriptModeFile(std::string const& scriptfile); /** * Set CMAKE_ARGC, CMAKE_ARGV0 ... variables. @@ -380,22 +388,26 @@ public: /** Get a cmSourceFile pointer for a given source name, if the name is * not found, then a null pointer is returned. */ - cmSourceFile* GetSource(const std::string& sourceName) const; + cmSourceFile* GetSource( + const std::string& sourceName, + cmSourceFileLocationKind kind = cmSourceFileLocationKind::Ambiguous) const; /** Create the source file and return it. generated * indicates if it is a generated file, this is used in determining * how to create the source file instance e.g. name */ - cmSourceFile* CreateSource(const std::string& sourceName, - bool generated = false); + cmSourceFile* CreateSource( + const std::string& sourceName, bool generated = false, + cmSourceFileLocationKind kind = cmSourceFileLocationKind::Ambiguous); /** Get a cmSourceFile pointer for a given source name, if the name is * not found, then create the source file and return it. generated * indicates if it is a generated file, this is used in determining * how to create the source file instance e.g. name */ - cmSourceFile* GetOrCreateSource(const std::string& sourceName, - bool generated = false); + cmSourceFile* GetOrCreateSource( + const std::string& sourceName, bool generated = false, + cmSourceFileLocationKind kind = cmSourceFileLocationKind::Ambiguous); void AddTargetObject(std::string const& tgtName, std::string const& objFile); @@ -432,8 +444,23 @@ public: /** Return whether the target platform is x32. */ bool PlatformIsx32() const; + /** Apple SDK Type */ + enum class AppleSDK + { + MacOS, + IPhoneOS, + IPhoneSimulator, + AppleTVOS, + AppleTVSimulator, + WatchOS, + WatchSimulator, + }; + + /** What SDK type points CMAKE_OSX_SYSROOT to? */ + AppleSDK GetAppleSDKType() const; + /** Return whether the target platform is Apple iOS. */ - bool PlatformIsAppleIos() const; + bool PlatformIsAppleEmbedded() const; /** Retrieve soname flag for the specified language if supported */ const char* GetSONameFlag(const std::string& language) const; @@ -446,7 +473,7 @@ public: /** * Make sure CMake can write this file */ - bool CanIWriteThisFile(const char* fileName) const; + bool CanIWriteThisFile(std::string const& fileName) const; #if defined(CMAKE_BUILD_WITH_CMAKE) /** @@ -489,7 +516,7 @@ public: /** * find what source group this source is in */ - cmSourceGroup* FindSourceGroup(const char* source, + cmSourceGroup* FindSourceGroup(const std::string& source, std::vector<cmSourceGroup>& groups) const; #endif @@ -561,7 +588,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 +666,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 +697,10 @@ public: { return this->InstallGenerators; } + const std::vector<cmInstallGenerator*>& GetInstallGenerators() const + { + return this->InstallGenerators; + } void AddTestGenerator(cmTestGenerator* g) { @@ -737,6 +773,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 +832,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 +848,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; @@ -828,8 +878,9 @@ protected: std::string DefineFlags; // Track the value of the computed DEFINITIONS property. - void AddDefineFlag(const char*, std::string&); - void RemoveDefineFlag(const char*, std::string::size_type, std::string&); + void AddDefineFlag(std::string const& flag, std::string&); + void RemoveDefineFlag(std::string const& flag, std::string::size_type, + std::string&); std::string DefineFlagsOrig; #if defined(CMAKE_BUILD_WITH_CMAKE) diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 801f72a..9bbc043 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -69,9 +69,6 @@ void cmMakefileExecutableTargetGenerator::WriteRuleFiles() this->WriteExecutableRule(true); } - // Write the requires target. - this->WriteTargetRequiresRules(); - // Write clean target this->WriteTargetCleanRules(); @@ -329,28 +326,28 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) outpath = this->Makefile->GetCurrentBinaryDirectory(); outpath += cmake::GetCMakeFilesDirectory(); outpath += "/CMakeRelink.dir"; - cmSystemTools::MakeDirectory(outpath.c_str()); + cmSystemTools::MakeDirectory(outpath); outpath += "/"; if (!targetNameImport.empty()) { outpathImp = outpath; } } else { - cmSystemTools::MakeDirectory(outpath.c_str()); + cmSystemTools::MakeDirectory(outpath); if (!targetNameImport.empty()) { outpathImp = this->GeneratorTarget->GetDirectory( this->ConfigName, cmStateEnums::ImportLibraryArtifact); - cmSystemTools::MakeDirectory(outpathImp.c_str()); + cmSystemTools::MakeDirectory(outpathImp); outpathImp += "/"; } } std::string compilePdbOutputPath = this->GeneratorTarget->GetCompilePDBDirectory(this->ConfigName); - cmSystemTools::MakeDirectory(compilePdbOutputPath.c_str()); + cmSystemTools::MakeDirectory(compilePdbOutputPath); std::string pdbOutputPath = this->GeneratorTarget->GetPDBDirectory(this->ConfigName); - cmSystemTools::MakeDirectory(pdbOutputPath.c_str()); + cmSystemTools::MakeDirectory(pdbOutputPath); pdbOutputPath += "/"; std::string targetFullPath = outpath + targetName; @@ -620,7 +617,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL); cmakeCommand += " -E __run_co_compile --lwyu="; cmakeCommand += targetOutPathReal; - real_link_commands.push_back(cmakeCommand); + real_link_commands.push_back(std::move(cmakeCommand)); } std::string launcher; @@ -669,7 +666,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) symlink += targetOutPathReal; symlink += " "; symlink += targetOutPath; - commands1.push_back(symlink); + commands1.push_back(std::move(symlink)); this->LocalGenerator->CreateCDCommand( commands1, this->Makefile->GetCurrentBinaryDirectory(), this->LocalGenerator->GetBinaryDirectory()); diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 80c62d1..9299ffe 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -89,9 +89,6 @@ void cmMakefileLibraryTargetGenerator::WriteRuleFiles() break; } - // Write the requires target. - this->WriteTargetRequiresRules(); - // Write clean target this->WriteTargetCleanRules(); @@ -528,30 +525,30 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( outpath = this->Makefile->GetCurrentBinaryDirectory(); outpath += cmake::GetCMakeFilesDirectory(); outpath += "/CMakeRelink.dir"; - cmSystemTools::MakeDirectory(outpath.c_str()); + cmSystemTools::MakeDirectory(outpath); outpath += "/"; if (!targetNameImport.empty()) { outpathImp = outpath; } } else { outpath = this->GeneratorTarget->GetDirectory(this->ConfigName); - cmSystemTools::MakeDirectory(outpath.c_str()); + cmSystemTools::MakeDirectory(outpath); outpath += "/"; if (!targetNameImport.empty()) { outpathImp = this->GeneratorTarget->GetDirectory( this->ConfigName, cmStateEnums::ImportLibraryArtifact); - cmSystemTools::MakeDirectory(outpathImp.c_str()); + cmSystemTools::MakeDirectory(outpathImp); outpathImp += "/"; } } std::string compilePdbOutputPath = this->GeneratorTarget->GetCompilePDBDirectory(this->ConfigName); - cmSystemTools::MakeDirectory(compilePdbOutputPath.c_str()); + cmSystemTools::MakeDirectory(compilePdbOutputPath); std::string pdbOutputPath = this->GeneratorTarget->GetPDBDirectory(this->ConfigName); - cmSystemTools::MakeDirectory(pdbOutputPath.c_str()); + cmSystemTools::MakeDirectory(pdbOutputPath); pdbOutputPath += "/"; std::string targetFullPath = outpath + targetName; @@ -900,7 +897,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( std::string cmd = launcher + acc; rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, cmd, vars); - real_link_commands.push_back(cmd); + real_link_commands.push_back(std::move(cmd)); } } // Append to the archive with the other object sets. @@ -910,7 +907,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( std::string cmd = launcher + aac; rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, cmd, vars); - real_link_commands.push_back(cmd); + real_link_commands.push_back(std::move(cmd)); } } // Finish the archive. @@ -921,7 +918,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( vars); // If there is no ranlib the command will be ":". Skip it. if (!cmd.empty() && cmd[0] != ':') { - real_link_commands.push_back(cmd); + real_link_commands.push_back(std::move(cmd)); } } } else { @@ -934,7 +931,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL); cmakeCommand += " -E __run_co_compile --lwyu="; cmakeCommand += targetOutPathReal; - real_link_commands.push_back(cmakeCommand); + real_link_commands.push_back(std::move(cmakeCommand)); } // Expand placeholders. @@ -975,7 +972,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( symlink += targetOutPathSO; symlink += " "; symlink += targetOutPath; - commands1.push_back(symlink); + commands1.push_back(std::move(symlink)); this->LocalGenerator->CreateCDCommand( commands1, this->Makefile->GetCurrentBinaryDirectory(), this->LocalGenerator->GetBinaryDirectory()); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 7db010c..73cf1f0 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -89,7 +89,7 @@ void cmMakefileTargetGenerator::CreateRuleFile() this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); this->TargetBuildDirectoryFull = this->LocalGenerator->ConvertToFullPath(this->TargetBuildDirectory); - cmSystemTools::MakeDirectory(this->TargetBuildDirectoryFull.c_str()); + cmSystemTools::MakeDirectory(this->TargetBuildDirectoryFull); // Construct the rule file name. this->BuildFileName = this->TargetBuildDirectory; @@ -200,10 +200,8 @@ void cmMakefileTargetGenerator::WriteCommonCodeRules() << "# Include any dependencies generated for this target.\n" << this->GlobalGenerator->IncludeDirective << " " << root << cmSystemTools::ConvertToOutputPath( - this->LocalGenerator - ->MaybeConvertToRelativePath( - this->LocalGenerator->GetBinaryDirectory(), dependFileNameFull) - .c_str()) + this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetBinaryDirectory(), dependFileNameFull)) << "\n\n"; if (!this->NoRuleMessages) { @@ -212,16 +210,14 @@ void cmMakefileTargetGenerator::WriteCommonCodeRules() << "# Include the progress variables for this target.\n" << this->GlobalGenerator->IncludeDirective << " " << root << cmSystemTools::ConvertToOutputPath( - this->LocalGenerator - ->MaybeConvertToRelativePath( - this->LocalGenerator->GetBinaryDirectory(), - this->ProgressFileNameFull) - .c_str()) + this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetBinaryDirectory(), + this->ProgressFileNameFull)) << "\n\n"; } // make sure the depend file exists - if (!cmSystemTools::FileExists(dependFileNameFull.c_str())) { + if (!cmSystemTools::FileExists(dependFileNameFull)) { // Write an empty dependency file. cmGeneratedFileStream depFileStream( dependFileNameFull.c_str(), false, @@ -250,11 +246,8 @@ void cmMakefileTargetGenerator::WriteCommonCodeRules() << "# Include the compile flags for this target's objects.\n" << this->GlobalGenerator->IncludeDirective << " " << root << cmSystemTools::ConvertToOutputPath( - this->LocalGenerator - ->MaybeConvertToRelativePath( - this->LocalGenerator->GetBinaryDirectory(), - this->FlagFileNameFull) - .c_str()) + this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetBinaryDirectory(), this->FlagFileNameFull)) << "\n\n"; } @@ -327,7 +320,7 @@ void cmMakefileTargetGenerator::MacOSXContentGeneratorType::operator()( copyCommand += " "; copyCommand += this->Generator->LocalGenerator->ConvertToOutputFormat( output, cmOutputConverter::SHELL); - commands.push_back(copyCommand); + commands.push_back(std::move(copyCommand)); this->Generator->LocalGenerator->WriteMakeRule( *this->Generator->BuildFileStream, nullptr, output, depends, commands, false); @@ -368,8 +361,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( // Create the directory containing the object file. This may be a // subdirectory under the target's directory. std::string dir = cmSystemTools::GetFilenamePath(obj); - cmSystemTools::MakeDirectory( - this->LocalGenerator->ConvertToFullPath(dir).c_str()); + cmSystemTools::MakeDirectory(this->LocalGenerator->ConvertToFullPath(dir)); // Save this in the target's list of object files. this->Objects.push_back(obj); @@ -425,6 +417,9 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( std::string config = this->LocalGenerator->GetConfigName(); std::string configUpper = cmSystemTools::UpperCase(config); + cmGeneratorExpressionInterpreter genexInterpreter( + this->LocalGenerator, this->GeneratorTarget, config, + this->GeneratorTarget->GetName(), lang); // Add Fortran format flags. if (lang == "Fortran") { @@ -432,34 +427,62 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( } // Add flags from source file properties. - if (const char* cflags = source.GetProperty("COMPILE_FLAGS")) { - cmGeneratorExpression ge; - std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(cflags); - const char* evaluatedFlags = cge->Evaluate(this->LocalGenerator, config, - false, this->GeneratorTarget); + const std::string COMPILE_FLAGS("COMPILE_FLAGS"); + if (const char* cflags = source.GetProperty(COMPILE_FLAGS)) { + const char* evaluatedFlags = + genexInterpreter.Evaluate(cflags, COMPILE_FLAGS); this->LocalGenerator->AppendFlags(flags, evaluatedFlags); *this->FlagFileStream << "# Custom flags: " << relativeObj << "_FLAGS = " << evaluatedFlags << "\n" << "\n"; } + const std::string COMPILE_OPTIONS("COMPILE_OPTIONS"); + if (const char* coptions = source.GetProperty(COMPILE_OPTIONS)) { + const char* evaluatedOptions = + genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS); + this->LocalGenerator->AppendCompileOptions(flags, evaluatedOptions); + *this->FlagFileStream << "# Custom options: " << relativeObj + << "_OPTIONS = " << evaluatedOptions << "\n" + << "\n"; + } + + // Add include directories from source file properties. + std::vector<std::string> includes; + + const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES"); + if (const char* cincludes = source.GetProperty(INCLUDE_DIRECTORIES)) { + const char* evaluatedIncludes = + genexInterpreter.Evaluate(cincludes, INCLUDE_DIRECTORIES); + this->LocalGenerator->AppendIncludeDirectories(includes, evaluatedIncludes, + source); + *this->FlagFileStream << "# Custom include directories: " << relativeObj + << "_INCLUDE_DIRECTORIES = " << evaluatedIncludes + << "\n" + << "\n"; + } + // Add language-specific defines. std::set<std::string> defines; - // Add source-sepcific preprocessor definitions. - if (const char* compile_defs = source.GetProperty("COMPILE_DEFINITIONS")) { - this->LocalGenerator->AppendDefines(defines, compile_defs); + // Add source-specific preprocessor definitions. + const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS"); + if (const char* compile_defs = source.GetProperty(COMPILE_DEFINITIONS)) { + const char* evaluatedDefs = + genexInterpreter.Evaluate(compile_defs, COMPILE_DEFINITIONS); + this->LocalGenerator->AppendDefines(defines, evaluatedDefs); *this->FlagFileStream << "# Custom defines: " << relativeObj - << "_DEFINES = " << compile_defs << "\n" + << "_DEFINES = " << evaluatedDefs << "\n" << "\n"; } std::string defPropName = "COMPILE_DEFINITIONS_"; defPropName += configUpper; if (const char* config_compile_defs = source.GetProperty(defPropName)) { - this->LocalGenerator->AppendDefines(defines, config_compile_defs); + const char* evaluatedDefs = + genexInterpreter.Evaluate(config_compile_defs, COMPILE_DEFINITIONS); + this->LocalGenerator->AppendDefines(defines, evaluatedDefs); *this->FlagFileStream << "# Custom defines: " << relativeObj << "_DEFINES_" - << configUpper << " = " << config_compile_defs - << "\n" + << configUpper << " = " << evaluatedDefs << "\n" << "\n"; } @@ -559,7 +582,10 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( vars.Defines = definesString.c_str(); - std::string const includesString = "$(" + lang + "_INCLUDES)"; + std::string includesString = this->LocalGenerator->GetIncludeFlags( + includes, this->GeneratorTarget, lang, true, false, config); + this->LocalGenerator->AppendFlags(includesString, + "$(" + lang + "_INCLUDES)"); vars.Includes = includesString.c_str(); // At the moment, it is assumed that C, C++, Fortran, and CUDA have both @@ -657,8 +683,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); @@ -763,7 +789,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( } else { std::string cmd = "$(CMAKE_COMMAND) -E cmake_unimplemented_variable "; cmd += preprocessRuleVar; - commands.push_back(cmd); + commands.push_back(std::move(cmd)); } this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr, @@ -810,7 +836,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( } else { std::string cmd = "$(CMAKE_COMMAND) -E cmake_unimplemented_variable "; cmd += assemblyRuleVar; - commands.push_back(cmd); + commands.push_back(std::move(cmd)); } this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr, @@ -818,65 +844,6 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( commands, false); } } - - // If the language needs provides-requires mode, create the - // corresponding targets. - std::string objectRequires = relativeObj; - objectRequires += ".requires"; - std::vector<std::string> p_depends; - // always provide an empty requires target - this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr, - objectRequires, p_depends, no_commands, - true); - - // write a build rule to recursively build what this obj provides - std::string objectProvides = relativeObj; - objectProvides += ".provides"; - std::string temp = relativeObj; - temp += ".provides.build"; - std::vector<std::string> r_commands; - std::string tgtMakefileName = - this->LocalGenerator->GetRelativeTargetDirectory(this->GeneratorTarget); - tgtMakefileName += "/build.make"; - r_commands.push_back( - this->LocalGenerator->GetRecursiveMakeCall(tgtMakefileName.c_str(), temp)); - - p_depends.clear(); - p_depends.push_back(objectRequires); - this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr, - objectProvides, p_depends, r_commands, - true); - - // write the provides.build rule dependency on the obj file - p_depends.clear(); - p_depends.push_back(relativeObj); - this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr, temp, - p_depends, no_commands, false); -} - -void cmMakefileTargetGenerator::WriteTargetRequiresRules() -{ - std::vector<std::string> depends; - std::vector<std::string> no_commands; - - // Construct the name of the dependency generation target. - std::string depTarget = - this->LocalGenerator->GetRelativeTargetDirectory(this->GeneratorTarget); - depTarget += "/requires"; - - // This target drives dependency generation for all object files. - std::string relPath = this->LocalGenerator->GetHomeRelativeOutputPath(); - std::string objTarget; - for (std::string const& obj : this->Objects) { - objTarget = relPath; - objTarget += obj; - objTarget += ".requires"; - depends.push_back(objTarget); - } - - // Write the rule. - this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr, - depTarget, depends, no_commands, true); } void cmMakefileTargetGenerator::WriteTargetCleanRules() @@ -937,7 +904,7 @@ bool cmMakefileTargetGenerator::WriteMakeRule( for (std::vector<std::string>::const_iterator o = outputs.begin() + 1; o != outputs.end(); ++o) { // Touch the extra output so "make" knows that it was updated, - // but only if the output was acually created. + // but only if the output was actually created. std::string const out = this->LocalGenerator->ConvertToOutputFormat( this->LocalGenerator->MaybeConvertToRelativePath(binDir, *o), cmOutputConverter::SHELL); @@ -1370,12 +1337,12 @@ void cmMakefileTargetGenerator::AppendObjectDepends( std::vector<std::string>& depends) { // Add dependencies on the compiled object files. - std::string relPath = this->LocalGenerator->GetHomeRelativeOutputPath(); - std::string objTarget; + std::string const& relPath = + this->LocalGenerator->GetHomeRelativeOutputPath(); for (std::string const& obj : this->Objects) { - objTarget = relPath; + std::string objTarget = relPath; objTarget += obj; - depends.push_back(objTarget); + depends.push_back(std::move(objTarget)); } // Add dependencies on the external object files. @@ -1466,8 +1433,8 @@ void cmMakefileTargetGenerator::CreateLinkScript( this->LocalGenerator->GetCurrentBinaryDirectory(), linkScriptName), cmOutputConverter::SHELL); link_command += " --verbose=$(VERBOSE)"; - makefile_commands.push_back(link_command); - makefile_depends.push_back(linkScriptName); + makefile_commands.push_back(std::move(link_command)); + makefile_depends.push_back(std::move(linkScriptName)); } bool cmMakefileTargetGenerator::CheckUseResponseFileForObjects( @@ -1539,7 +1506,7 @@ std::string cmMakefileTargetGenerator::CreateResponseFile( // Add a dependency so the target will rebuild when the set of // objects changes. - makefile_depends.push_back(responseFileNameFull); + makefile_depends.push_back(std::move(responseFileNameFull)); // Construct the name to be used on the command line. std::string responseFileName = this->TargetBuildDirectory; @@ -1678,10 +1645,17 @@ void cmMakefileTargetGenerator::AddIncludeFlags(std::string& flags, } if (useResponseFile) { + std::string const responseFlagVar = + "CMAKE_" + lang + "_RESPONSE_FILE_FLAG"; + std::string responseFlag = + this->Makefile->GetSafeDefinition(responseFlagVar); + if (responseFlag.empty()) { + responseFlag = "@"; + } std::string name = "includes_"; name += lang; name += ".rsp"; - std::string arg = "@" + + std::string arg = std::move(responseFlag) + this->CreateResponseFile(name.c_str(), includeFlags, this->FlagFileDepends[lang]); this->LocalGenerator->AppendFlags(flags, arg); diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h index 5ab7e36..7af3cf3 100644 --- a/Source/cmMakefileTargetGenerator.h +++ b/Source/cmMakefileTargetGenerator.h @@ -63,9 +63,6 @@ protected: void WriteCommonCodeRules(); void WriteTargetLanguageFlags(); - // write the provide require rules for this target - void WriteTargetRequiresRules(); - // write the clean rules for this target void WriteTargetCleanRules(); diff --git a/Source/cmMakefileUtilityTargetGenerator.cxx b/Source/cmMakefileUtilityTargetGenerator.cxx index 46df0d8..8fbd5d2 100644 --- a/Source/cmMakefileUtilityTargetGenerator.cxx +++ b/Source/cmMakefileUtilityTargetGenerator.cxx @@ -4,6 +4,7 @@ #include <ostream> #include <string> +#include <utility> #include <vector> #include "cmGeneratedFileStream.h" @@ -45,11 +46,9 @@ void cmMakefileUtilityTargetGenerator::WriteRuleFiles() << "# Include the progress variables for this target.\n" << this->GlobalGenerator->IncludeDirective << " " << root << cmSystemTools::ConvertToOutputPath( - this->LocalGenerator - ->MaybeConvertToRelativePath( - this->LocalGenerator->GetBinaryDirectory(), - this->ProgressFileNameFull) - .c_str()) + this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetBinaryDirectory(), + this->ProgressFileNameFull)) << "\n\n"; } @@ -90,7 +89,7 @@ void cmMakefileUtilityTargetGenerator::WriteRuleFiles() if (depends.empty() && commands.empty()) { std::string hack = this->GlobalGenerator->GetEmptyRuleHackDepends(); if (!hack.empty()) { - depends.push_back(hack); + depends.push_back(std::move(hack)); } } 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/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index e0cc35a..ddbc772 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -498,13 +498,12 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd() cmakeCommand += " -E __run_co_compile --lwyu="; cmGeneratorTarget& gt = *this->GetGeneratorTarget(); const std::string cfgName = this->GetConfigName(); - std::string targetOutput = ConvertToNinjaPath(gt.GetFullPath(cfgName)); std::string targetOutputReal = this->ConvertToNinjaPath( gt.GetFullPath(cfgName, cmStateEnums::RuntimeBinaryArtifact, /*realname=*/true)); cmakeCommand += targetOutputReal; cmakeCommand += " || true"; - linkCmds.push_back(cmakeCommand); + linkCmds.push_back(std::move(cmakeCommand)); } return linkCmds; } @@ -686,16 +685,11 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() } } - cmNinjaDeps byproducts; - if (!this->TargetNameImport.empty()) { const std::string impLibPath = localGen.ConvertToOutputFormat( targetOutputImplib, cmOutputConverter::SHELL); vars["TARGET_IMPLIB"] = impLibPath; EnsureParentDirectoryExists(impLibPath); - if (genTarget.HasImportLibrary()) { - byproducts.push_back(targetOutputImplib); - } } const std::string objPath = GetGeneratorTarget()->GetSupportDirectory(); @@ -713,29 +707,6 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() std::replace(link_path.begin(), link_path.end(), '\\', '/'); } - const std::vector<cmCustomCommand>* cmdLists[3] = { - &genTarget.GetPreBuildCommands(), &genTarget.GetPreLinkCommands(), - &genTarget.GetPostBuildCommands() - }; - - std::vector<std::string> preLinkCmdLines, postBuildCmdLines; - vars["PRE_LINK"] = localGen.BuildCommandLine(preLinkCmdLines); - vars["POST_BUILD"] = localGen.BuildCommandLine(postBuildCmdLines); - - std::vector<std::string>* cmdLineLists[3] = { &preLinkCmdLines, - &preLinkCmdLines, - &postBuildCmdLines }; - - for (unsigned i = 0; i != 3; ++i) { - for (cmCustomCommand const& cc : *cmdLists[i]) { - cmCustomCommandGenerator ccg(cc, cfgName, this->GetLocalGenerator()); - localGen.AppendCustomCommandLines(ccg, *cmdLineLists[i]); - std::vector<std::string> const& ccByproducts = ccg.GetByproducts(); - std::transform(ccByproducts.begin(), ccByproducts.end(), - std::back_inserter(byproducts), MapToNinjaPath()); - } - } - cmGlobalNinjaGenerator& globalGen = *this->GetGlobalGenerator(); // Device linking currently doesn't support response files so @@ -760,7 +731,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() /*implicitOuts=*/cmNinjaDeps(), explicitDeps, implicitDeps, orderOnlyDeps, vars, rspfile, commandLineLengthLimit, &usedResponseFile); - this->WriteDeviceLinkRule(usedResponseFile); + this->WriteDeviceLinkRule(false); } void cmNinjaNormalTargetGenerator::WriteLinkStatement() @@ -978,7 +949,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() std::string obj_list_file = mdi->DefFile + ".objs"; cmd += this->GetLocalGenerator()->ConvertToOutputFormat( obj_list_file, cmOutputConverter::SHELL); - preLinkCmdLines.push_back(cmd); + preLinkCmdLines.push_back(std::move(cmd)); // create a list of obj files for the -E __create_def to read cmGeneratedFileStream fout(obj_list_file.c_str()); diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 5805259..f4faf47 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -135,13 +135,21 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject( } // Add source file specific flags. - if (const char* cflags = source->GetProperty("COMPILE_FLAGS")) { - std::string config = this->LocalGenerator->GetConfigName(); - cmGeneratorExpression ge; - std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(cflags); - const char* evaluatedFlags = cge->Evaluate(this->LocalGenerator, config, - false, this->GeneratorTarget); - this->LocalGenerator->AppendFlags(flags, evaluatedFlags); + cmGeneratorExpressionInterpreter genexInterpreter( + this->LocalGenerator, this->GeneratorTarget, + this->LocalGenerator->GetConfigName(), this->GeneratorTarget->GetName(), + language); + + const std::string COMPILE_FLAGS("COMPILE_FLAGS"); + if (const char* cflags = source->GetProperty(COMPILE_FLAGS)) { + this->LocalGenerator->AppendFlags( + flags, genexInterpreter.Evaluate(cflags, COMPILE_FLAGS)); + } + + const std::string COMPILE_OPTIONS("COMPILE_OPTIONS"); + if (const char* coptions = source->GetProperty(COMPILE_OPTIONS)) { + this->LocalGenerator->AppendCompileOptions( + flags, genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS)); } return flags; @@ -178,13 +186,23 @@ std::string cmNinjaTargetGenerator::ComputeDefines(cmSourceFile const* source, const std::string& language) { std::set<std::string> defines; - this->LocalGenerator->AppendDefines( - defines, source->GetProperty("COMPILE_DEFINITIONS")); - { - std::string defPropName = "COMPILE_DEFINITIONS_"; - defPropName += cmSystemTools::UpperCase(this->GetConfigName()); - this->LocalGenerator->AppendDefines(defines, - source->GetProperty(defPropName)); + const std::string config = this->LocalGenerator->GetConfigName(); + cmGeneratorExpressionInterpreter genexInterpreter( + this->LocalGenerator, this->GeneratorTarget, config, + this->GeneratorTarget->GetName(), language); + + const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS"); + if (const char* compile_defs = source->GetProperty(COMPILE_DEFINITIONS)) { + this->LocalGenerator->AppendDefines( + defines, genexInterpreter.Evaluate(compile_defs, COMPILE_DEFINITIONS)); + } + + std::string defPropName = "COMPILE_DEFINITIONS_"; + defPropName += cmSystemTools::UpperCase(config); + if (const char* config_compile_defs = source->GetProperty(defPropName)) { + this->LocalGenerator->AppendDefines( + defines, + genexInterpreter.Evaluate(config_compile_defs, COMPILE_DEFINITIONS)); } std::string definesString = this->GetDefines(language); @@ -193,6 +211,30 @@ std::string cmNinjaTargetGenerator::ComputeDefines(cmSourceFile const* source, return definesString; } +std::string cmNinjaTargetGenerator::ComputeIncludes( + cmSourceFile const* source, const std::string& language) +{ + std::vector<std::string> includes; + const std::string config = this->LocalGenerator->GetConfigName(); + cmGeneratorExpressionInterpreter genexInterpreter( + this->LocalGenerator, this->GeneratorTarget, config, + this->GeneratorTarget->GetName(), language); + + const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES"); + if (const char* cincludes = source->GetProperty(INCLUDE_DIRECTORIES)) { + this->LocalGenerator->AppendIncludeDirectories( + includes, genexInterpreter.Evaluate(cincludes, INCLUDE_DIRECTORIES), + *source); + } + + std::string includesString = this->LocalGenerator->GetIncludeFlags( + includes, this->GeneratorTarget, language, true, false, config); + this->LocalGenerator->AppendFlags(includesString, + this->GetIncludes(language)); + + return includesString; +} + cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps() const { // Static libraries never depend on other targets for linking. @@ -405,14 +447,20 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) std::string flags = "$FLAGS"; std::string rspfile; std::string rspcontent; - std::string responseFlag; bool const lang_supports_response = !(lang == "RC" || lang == "CUDA"); if (lang_supports_response && this->ForceResponseFile()) { + std::string const responseFlagVar = + "CMAKE_" + lang + "_RESPONSE_FILE_FLAG"; + std::string responseFlag = + this->Makefile->GetSafeDefinition(responseFlagVar); + if (responseFlag.empty()) { + responseFlag = "@"; + } rspfile = "$RSP_FILE"; - responseFlag = "@" + rspfile; + responseFlag += rspfile; rspcontent = " $DEFINES $INCLUDES $FLAGS"; - flags = responseFlag; + flags = std::move(responseFlag); vars.Defines = ""; vars.Includes = ""; } @@ -647,7 +695,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) { @@ -807,7 +855,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( cmNinjaVars vars; vars["FLAGS"] = this->ComputeFlagsForObject(source, language); vars["DEFINES"] = this->ComputeDefines(source, language); - vars["INCLUDES"] = this->GetIncludes(language); + vars["INCLUDES"] = this->ComputeIncludes(source, language); if (!this->NeedDepTypeMSVC(language)) { vars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat( objectFileName + ".d", cmOutputConverter::SHELL); @@ -1035,7 +1083,7 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand( std::string escapedSourceFileName = sourceFileName; - if (!cmSystemTools::FileIsFullPath(sourceFileName.c_str())) { + if (!cmSystemTools::FileIsFullPath(sourceFileName)) { escapedSourceFileName = cmSystemTools::CollapseFullPath( escapedSourceFileName, this->GetGlobalGenerator() ->GetCMakeInstance() @@ -1095,8 +1143,8 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand( void cmNinjaTargetGenerator::EnsureDirectoryExists( const std::string& path) const { - if (cmSystemTools::FileIsFullPath(path.c_str())) { - cmSystemTools::MakeDirectory(path.c_str()); + if (cmSystemTools::FileIsFullPath(path)) { + cmSystemTools::MakeDirectory(path); } else { cmGlobalNinjaGenerator* gg = this->GetGlobalGenerator(); std::string fullPath = @@ -1104,7 +1152,7 @@ void cmNinjaTargetGenerator::EnsureDirectoryExists( // Also ensures their is a trailing slash. gg->StripNinjaOutputPathPrefixAsSuffix(fullPath); fullPath += path; - cmSystemTools::MakeDirectory(fullPath.c_str()); + cmSystemTools::MakeDirectory(fullPath); } } @@ -1140,7 +1188,7 @@ void cmNinjaTargetGenerator::MacOSXContentGeneratorType::operator()( output); // Add as a dependency to the target so that it gets called. - this->Generator->ExtraFiles.push_back(output); + this->Generator->ExtraFiles.push_back(std::move(output)); } void cmNinjaTargetGenerator::addPoolNinjaVariable( diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h index 770a99d..4660a3a 100644 --- a/Source/cmNinjaTargetGenerator.h +++ b/Source/cmNinjaTargetGenerator.h @@ -82,6 +82,9 @@ protected: std::string ComputeDefines(cmSourceFile const* source, const std::string& language); + std::string ComputeIncludes(cmSourceFile const* source, + const std::string& language); + std::string ConvertToNinjaPath(const std::string& path) const { return this->GetGlobalGenerator()->ConvertToNinjaPath(path); diff --git a/Source/cmOSXBundleGenerator.cxx b/Source/cmOSXBundleGenerator.cxx index c85c82d..2b96785 100644 --- a/Source/cmOSXBundleGenerator.cxx +++ b/Source/cmOSXBundleGenerator.cxx @@ -43,7 +43,7 @@ void cmOSXBundleGenerator::CreateAppBundle(const std::string& targetName, out += "/"; out += this->GT->GetAppBundleDirectory(this->ConfigName, cmGeneratorTarget::FullLevel); - cmSystemTools::MakeDirectory(out.c_str()); + cmSystemTools::MakeDirectory(out); this->Makefile->AddCMakeOutputFile(out); // Configure the Info.plist file. Note that it needs the executable name @@ -82,7 +82,7 @@ void cmOSXBundleGenerator::CreateFramework(const std::string& targetName, // Configure the Info.plist file std::string plist = newoutpath; - if (!this->Makefile->PlatformIsAppleIos()) { + if (!this->Makefile->PlatformIsAppleEmbedded()) { // Put the Info.plist file into the Resources directory. this->MacContentFolders->insert("Resources"); plist += "/Resources"; @@ -93,7 +93,7 @@ void cmOSXBundleGenerator::CreateFramework(const std::string& targetName, plist.c_str()); // Generate Versions directory only for MacOSX frameworks - if (this->Makefile->PlatformIsAppleIos()) { + if (this->Makefile->PlatformIsAppleEmbedded()) { return; } @@ -105,10 +105,10 @@ void cmOSXBundleGenerator::CreateFramework(const std::string& targetName, // Make foo.framework/Versions std::string versions = contentdir; versions += "Versions"; - cmSystemTools::MakeDirectory(versions.c_str()); + cmSystemTools::MakeDirectory(versions); // Make foo.framework/Versions/version - cmSystemTools::MakeDirectory(newoutpath.c_str()); + cmSystemTools::MakeDirectory(newoutpath); // Current -> version oldName = frameworkVersion; @@ -173,7 +173,7 @@ void cmOSXBundleGenerator::CreateCFBundle(const std::string& targetName, out += "/"; out += this->GT->GetCFBundleDirectory(this->ConfigName, cmGeneratorTarget::FullLevel); - cmSystemTools::MakeDirectory(out.c_str()); + cmSystemTools::MakeDirectory(out); this->Makefile->AddCMakeOutputFile(out); // Configure the Info.plist file. Note that it needs the executable name @@ -213,7 +213,7 @@ std::string cmOSXBundleGenerator::InitMacOSXContentDirectory( this->ConfigName, cmStateEnums::RuntimeBinaryArtifact); macdir += "/"; macdir += pkgloc; - cmSystemTools::MakeDirectory(macdir.c_str()); + cmSystemTools::MakeDirectory(macdir); // Record use of this content location. Only the first level // directory is needed. diff --git a/Source/cmOrderDirectories.cxx b/Source/cmOrderDirectories.cxx index 27ad710..04a9318 100644 --- a/Source/cmOrderDirectories.cxx +++ b/Source/cmOrderDirectories.cxx @@ -118,7 +118,7 @@ bool cmOrderDirectoriesConstraint::FileMayConflict(std::string const& dir, std::string file = dir; file += "/"; file += name; - if (cmSystemTools::FileExists(file.c_str(), true)) { + if (cmSystemTools::FileExists(file, true)) { // The file conflicts only if it is not the same as the original // file due to a symlink or hardlink. return !cmSystemTools::SameFile(this->FullPath, file); diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index dac6569..25db929 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -29,7 +29,7 @@ std::string cmOutputConverter::ConvertToOutputForExisting( // space. if (this->GetState()->UseWindowsShell() && remote.find(' ') != std::string::npos && - cmSystemTools::FileExists(remote.c_str())) { + cmSystemTools::FileExists(remote)) { std::string tmp; if (cmSystemTools::GetShortPath(remote, tmp)) { return this->ConvertToOutputFormat(tmp, format); @@ -125,7 +125,7 @@ std::string cmOutputConverter::ForceToRelativePath( assert(local_path.empty() || local_path[local_path.size() - 1] != '/'); // If the path is already relative then just return the path. - if (!cmSystemTools::FileIsFullPath(remote_path.c_str())) { + if (!cmSystemTools::FileIsFullPath(remote_path)) { return remote_path; } diff --git a/Source/cmOutputRequiredFilesCommand.cxx b/Source/cmOutputRequiredFilesCommand.cxx index cde9037..bdb98ca 100644 --- a/Source/cmOutputRequiredFilesCommand.cxx +++ b/Source/cmOutputRequiredFilesCommand.cxx @@ -173,7 +173,7 @@ protected: std::string line; while (cmSystemTools::GetLineFromStream(fin, line)) { - if (cmHasLiteralPrefix(line.c_str(), "#include")) { + if (cmHasLiteralPrefix(line, "#include")) { // if it is an include line then create a string class size_t qstart = line.find('\"', 8); size_t qend; @@ -213,51 +213,51 @@ protected: cxxFile = root + ".cxx"; bool found = false; // try jumping to .cxx .cpp and .c in order - if (cmSystemTools::FileExists(cxxFile.c_str())) { + if (cmSystemTools::FileExists(cxxFile)) { found = true; } for (std::string path : this->IncludeDirectories) { path = path + "/"; path = path + cxxFile; - if (cmSystemTools::FileExists(path.c_str())) { + if (cmSystemTools::FileExists(path)) { found = true; } } if (!found) { cxxFile = root + ".cpp"; - if (cmSystemTools::FileExists(cxxFile.c_str())) { + if (cmSystemTools::FileExists(cxxFile)) { found = true; } for (std::string path : this->IncludeDirectories) { path = path + "/"; path = path + cxxFile; - if (cmSystemTools::FileExists(path.c_str())) { + if (cmSystemTools::FileExists(path)) { found = true; } } } if (!found) { cxxFile = root + ".c"; - if (cmSystemTools::FileExists(cxxFile.c_str())) { + if (cmSystemTools::FileExists(cxxFile)) { found = true; } for (std::string path : this->IncludeDirectories) { path = path + "/"; path = path + cxxFile; - if (cmSystemTools::FileExists(path.c_str())) { + if (cmSystemTools::FileExists(path)) { found = true; } } } if (!found) { cxxFile = root + ".txx"; - if (cmSystemTools::FileExists(cxxFile.c_str())) { + if (cmSystemTools::FileExists(cxxFile)) { found = true; } for (std::string path : this->IncludeDirectories) { path = path + "/"; path = path + cxxFile; - if (cmSystemTools::FileExists(path.c_str())) { + if (cmSystemTools::FileExists(path)) { found = true; } } @@ -426,7 +426,7 @@ protected: path = path + "/"; } path = path + fname; - if (cmSystemTools::FileExists(path.c_str(), true) && + if (cmSystemTools::FileExists(path, true) && !cmSystemTools::FileIsDirectory(path)) { std::string fp = cmSystemTools::CollapseFullPath(path); this->DirectoryToFileToPathMap[extraPath ? extraPath : ""][fname] = fp; @@ -440,7 +440,7 @@ protected: path = path + "/"; } path = path + fname; - if (cmSystemTools::FileExists(path.c_str(), true) && + if (cmSystemTools::FileExists(path, true) && !cmSystemTools::FileIsDirectory(path)) { std::string fp = cmSystemTools::CollapseFullPath(path); this->DirectoryToFileToPathMap[extraPath][fname] = fp; diff --git a/Source/cmParseArgumentsCommand.cxx b/Source/cmParseArgumentsCommand.cxx index 0922e6e..9a5b097 100644 --- a/Source/cmParseArgumentsCommand.cxx +++ b/Source/cmParseArgumentsCommand.cxx @@ -71,8 +71,8 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args, typedef std::map<std::string, std::string> single_map; typedef std::map<std::string, std::vector<std::string>> multi_map; options_map options; - single_map single; - multi_map multi; + single_map singleValArgs; + multi_map multiValArgs; // anything else is put into a vector of unparsed strings std::vector<std::string> unparsed; @@ -98,7 +98,7 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args, if (!used_keywords.insert(iter).second) { this->GetMakefile()->IssueMessage(cmake::WARNING, dup_warning + iter); } - single[iter]; // default initialize + singleValArgs[iter]; // default initialize } // the fourth argument is a (cmake) list of multi argument options @@ -108,7 +108,7 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args, if (!used_keywords.insert(iter).second) { this->GetMakefile()->IssueMessage(cmake::WARNING, dup_warning + iter); } - multi[iter]; // default initialize + multiValArgs[iter]; // default initialize } enum insideValues @@ -161,15 +161,15 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args, continue; } - const single_map::iterator singleIter = single.find(arg); - if (singleIter != single.end()) { + const single_map::iterator singleIter = singleValArgs.find(arg); + if (singleIter != singleValArgs.end()) { insideValues = SINGLE; currentArgName = arg; continue; } - const multi_map::iterator multiIter = multi.find(arg); - if (multiIter != multi.end()) { + const multi_map::iterator multiIter = multiValArgs.find(arg); + if (multiIter != multiValArgs.end()) { insideValues = MULTI; currentArgName = arg; continue; @@ -177,14 +177,14 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args, switch (insideValues) { case SINGLE: - single[currentArgName] = arg; + singleValArgs[currentArgName] = arg; insideValues = NONE; break; case MULTI: if (parseFromArgV) { - multi[currentArgName].push_back(escape_arg(arg)); + multiValArgs[currentArgName].push_back(escape_arg(arg)); } else { - multi[currentArgName].push_back(arg); + multiValArgs[currentArgName].push_back(arg); } break; default: @@ -204,7 +204,7 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args, this->Makefile->AddDefinition(prefix + iter.first, iter.second ? "TRUE" : "FALSE"); } - for (auto const& iter : single) { + for (auto const& iter : singleValArgs) { if (!iter.second.empty()) { this->Makefile->AddDefinition(prefix + iter.first, iter.second.c_str()); } else { @@ -212,7 +212,7 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args, } } - for (auto const& iter : multi) { + for (auto const& iter : multiValArgs) { if (!iter.second.empty()) { this->Makefile->AddDefinition( prefix + iter.first, cmJoin(cmMakeRange(iter.second), ";").c_str()); 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/cmProcessOutput.cxx b/Source/cmProcessOutput.cxx index 617e1ca..8371706 100644 --- a/Source/cmProcessOutput.cxx +++ b/Source/cmProcessOutput.cxx @@ -13,7 +13,7 @@ cmProcessOutput::Encoding cmProcessOutput::FindEncoding( std::string const& name) { Encoding encoding = Auto; - if (name == "UTF8") { + if ((name == "UTF8") || (name == "UTF-8")) { encoding = UTF8; } else if (name == "NONE") { encoding = None; diff --git a/Source/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx index fea8a9d..dfa1858 100644 --- a/Source/cmProjectCommand.cxx +++ b/Source/cmProjectCommand.cxx @@ -98,7 +98,7 @@ bool cmProjectCommand::InitialPass(std::vector<std::string> const& args, } else if (args[i] == "DESCRIPTION") { if (haveDescription) { this->Makefile->IssueMessage( - cmake::FATAL_ERROR, "DESCRITPION may be specified at most once."); + cmake::FATAL_ERROR, "DESCRIPTION may be specified at most once."); cmSystemTools::SetFatalErrorOccured(); return true; } diff --git a/Source/cmQTWrapCPPCommand.cxx b/Source/cmQTWrapCPPCommand.cxx index ae1fdfa..09cc63a 100644 --- a/Source/cmQTWrapCPPCommand.cxx +++ b/Source/cmQTWrapCPPCommand.cxx @@ -7,6 +7,8 @@ #include "cmSourceFile.h" #include "cmSystemTools.h" +#include <utility> + class cmExecutionStatus; // cmQTWrapCPPCommand @@ -45,7 +47,7 @@ bool cmQTWrapCPPCommand::InitialPass(std::vector<std::string> const& args, // Compute the name of the header from which to generate the file. std::string hname; - if (cmSystemTools::FileIsFullPath(j->c_str())) { + if (cmSystemTools::FileIsFullPath(*j)) { hname = *j; } else { if (curr && curr->GetPropertyAsBool("GENERATED")) { @@ -71,7 +73,7 @@ bool cmQTWrapCPPCommand::InitialPass(std::vector<std::string> const& args, commandLine.push_back(hname); cmCustomCommandLines commandLines; - commandLines.push_back(commandLine); + commandLines.push_back(std::move(commandLine)); std::vector<std::string> depends; depends.push_back(moc_exe); diff --git a/Source/cmQTWrapUICommand.cxx b/Source/cmQTWrapUICommand.cxx index 3d586d6..da36cdf 100644 --- a/Source/cmQTWrapUICommand.cxx +++ b/Source/cmQTWrapUICommand.cxx @@ -7,6 +7,8 @@ #include "cmSourceFile.h" #include "cmSystemTools.h" +#include <utility> + class cmExecutionStatus; // cmQTWrapUICommand @@ -53,7 +55,7 @@ bool cmQTWrapUICommand::InitialPass(std::vector<std::string> const& args, // Compute the name of the ui file from which to generate others. std::string uiName; - if (cmSystemTools::FileIsFullPath(j->c_str())) { + if (cmSystemTools::FileIsFullPath(*j)) { uiName = *j; } else { if (curr && curr->GetPropertyAsBool("GENERATED")) { @@ -86,7 +88,7 @@ bool cmQTWrapUICommand::InitialPass(std::vector<std::string> const& args, hCommand.push_back(hName); hCommand.push_back(uiName); cmCustomCommandLines hCommandLines; - hCommandLines.push_back(hCommand); + hCommandLines.push_back(std::move(hCommand)); cmCustomCommandLine cxxCommand; cxxCommand.push_back(uic_exe); @@ -96,7 +98,7 @@ bool cmQTWrapUICommand::InitialPass(std::vector<std::string> const& args, cxxCommand.push_back(cxxName); cxxCommand.push_back(uiName); cmCustomCommandLines cxxCommandLines; - cxxCommandLines.push_back(cxxCommand); + cxxCommandLines.push_back(std::move(cxxCommand)); cmCustomCommandLine mocCommand; mocCommand.push_back(moc_exe); @@ -104,7 +106,7 @@ bool cmQTWrapUICommand::InitialPass(std::vector<std::string> const& args, mocCommand.push_back(mocName); mocCommand.push_back(hName); cmCustomCommandLines mocCommandLines; - mocCommandLines.push_back(mocCommand); + mocCommandLines.push_back(std::move(mocCommand)); std::vector<std::string> depends; depends.push_back(uiName); diff --git a/Source/cmQtAutoGen.cxx b/Source/cmQtAutoGen.cxx index 0fc2fc0..6e9ca44 100644 --- a/Source/cmQtAutoGen.cxx +++ b/Source/cmQtAutoGen.cxx @@ -2,15 +2,13 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmQtAutoGen.h" #include "cmAlgorithms.h" -#include "cmProcessOutput.h" #include "cmSystemTools.h" -#include "cmsys/FStream.hxx" #include "cmsys/RegularExpression.hxx" #include <algorithm> +#include <iterator> #include <sstream> -#include <stddef.h> // - Static variables @@ -19,10 +17,6 @@ std::string const genNameMoc = "AutoMoc"; std::string const genNameUic = "AutoUic"; std::string const genNameRcc = "AutoRcc"; -std::string const mcNameSingle = "SINGLE"; -std::string const mcNameWrap = "WRAP"; -std::string const mcNameFull = "FULL"; - // - Static functions /// @brief Merges newOpts into baseOpts @@ -79,221 +73,31 @@ 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, - std::vector<std::string>& files, - std::string* errorMessage) -{ - bool allGood = true; - // Read qrc file content into string - std::string qrcContents; - { - cmsys::ifstream ifs(fileName.c_str()); - if (ifs) { - std::ostringstream osst; - osst << ifs.rdbuf(); - qrcContents = osst.str(); - } else { - if (errorMessage != nullptr) { - std::ostringstream ost; - ost << "rcc file not readable:\n" - << " " << cmQtAutoGen::Quoted(fileName) << "\n"; - *errorMessage = ost.str(); - } - allGood = false; - } - } - if (allGood) { - // qrc file directory - std::string qrcDir(cmSystemTools::GetFilenamePath(fileName)); - if (!qrcDir.empty()) { - qrcDir += '/'; - } - - cmsys::RegularExpression fileMatchRegex("(<file[^<]+)"); - cmsys::RegularExpression fileReplaceRegex("(^<file[^>]*>)"); - - size_t offset = 0; - while (fileMatchRegex.find(qrcContents.c_str() + offset)) { - std::string qrcEntry = fileMatchRegex.match(1); - offset += qrcEntry.size(); - { - fileReplaceRegex.find(qrcEntry); - std::string tag = fileReplaceRegex.match(1); - qrcEntry = qrcEntry.substr(tag.size()); - } - if (!cmSystemTools::FileIsFullPath(qrcEntry.c_str())) { - qrcEntry = qrcDir + qrcEntry; - } - files.push_back(qrcEntry); - } - } - return allGood; -} - -/// @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::string const& fileName, - std::vector<std::string>& files, - std::string* errorMessage) -{ - if (rccCommand.empty()) { - cmSystemTools::Error("rcc executable not available"); - 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); - - // Run rcc list command - bool result = false; - int retVal = 0; - std::string rccStdOut; - std::string rccStdErr; - { - std::vector<std::string> command; - command.push_back(rccCommand); - command.push_back(hasDashDashList ? "--list" : "-list"); - command.push_back(fileNameName); - result = cmSystemTools::RunSingleCommand( - command, &rccStdOut, &rccStdErr, &retVal, fileDir.c_str(), - cmSystemTools::OUTPUT_NONE, 0.0, cmProcessOutput::Auto); - } - 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(); - } - return false; - } - - // Parse rcc std output - { - std::istringstream ostr(rccStdOut); - std::string oline; - while (std::getline(ostr, oline)) { - oline = utilStripCR(oline); - if (!oline.empty()) { - files.push_back(oline); - } - } - } - // Parse rcc error output - { - std::istringstream estr(rccStdErr); - std::string eline; - while (std::getline(estr, eline)) { - eline = utilStripCR(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(); - } - return false; - } - pos += searchString.length(); - std::string::size_type sz = eline.size() - pos - 1; - files.push_back(eline.substr(pos, sz)); - } - } - } - - // Convert relative paths to absolute paths - for (std::string& resFile : files) { - resFile = cmSystemTools::CollapseCombinedPath(fileDir, resFile); - } - - return true; -} - // - Class definitions -std::string const cmQtAutoGen::listSep = "<<<S>>>"; +std::string const cmQtAutoGen::ListSep = "<<<S>>>"; +unsigned int const cmQtAutoGen::ParallelMax = 64; -std::string const& cmQtAutoGen::GeneratorName(Generator type) +std::string const& cmQtAutoGen::GeneratorName(GeneratorT type) { switch (type) { - case Generator::GEN: + case GeneratorT::GEN: return genNameGen; - case Generator::MOC: + case GeneratorT::MOC: return genNameMoc; - case Generator::UIC: + case GeneratorT::UIC: return genNameUic; - case Generator::RCC: + case GeneratorT::RCC: return genNameRcc; } return genNameGen; } -std::string cmQtAutoGen::GeneratorNameUpper(Generator genType) +std::string cmQtAutoGen::GeneratorNameUpper(GeneratorT genType) { return cmSystemTools::UpperCase(cmQtAutoGen::GeneratorName(genType)); } -std::string const& cmQtAutoGen::MultiConfigName(MultiConfig config) -{ - switch (config) { - case MultiConfig::SINGLE: - return mcNameSingle; - case MultiConfig::WRAP: - return mcNameWrap; - case MultiConfig::FULL: - return mcNameFull; - } - return mcNameWrap; -} - -cmQtAutoGen::MultiConfig cmQtAutoGen::MultiConfigType(std::string const& name) -{ - if (name == mcNameSingle) { - return MultiConfig::SINGLE; - } - if (name == mcNameFull) { - return MultiConfig::FULL; - } - return MultiConfig::WRAP; -} - std::string cmQtAutoGen::Quoted(std::string const& text) { static const char* rep[18] = { "\\", "\\\\", "\"", "\\\"", "\a", "\\a", @@ -301,8 +105,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; @@ -310,6 +113,33 @@ std::string cmQtAutoGen::Quoted(std::string const& text) return res; } +std::string cmQtAutoGen::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; +} + +std::string cmQtAutoGen::SubDirPrefix(std::string const& filename) +{ + std::string res(cmSystemTools::GetFilenamePath(filename)); + if (!res.empty()) { + res += '/'; + } + return res; +} + std::string cmQtAutoGen::AppendFilenameSuffix(std::string const& filename, std::string const& suffix) { @@ -349,26 +179,79 @@ void cmQtAutoGen::RccMergeOptions(std::vector<std::string>& baseOpts, MergeOptions(baseOpts, newOpts, valueOpts, isQt5); } -bool cmQtAutoGen::RccListInputs(std::string const& qtMajorVersion, - std::string const& rccCommand, - std::string const& fileName, - std::vector<std::string>& files, - std::string* errorMessage) +void cmQtAutoGen::RccListParseContent(std::string const& content, + std::vector<std::string>& files) { - bool allGood = false; - if (cmSystemTools::FileExists(fileName.c_str())) { - if (qtMajorVersion == "4") { - allGood = RccListInputsQt4(fileName, files, errorMessage); - } else { - allGood = RccListInputsQt5(rccCommand, fileName, files, errorMessage); + cmsys::RegularExpression fileMatchRegex("(<file[^<]+)"); + cmsys::RegularExpression fileReplaceRegex("(^<file[^>]*>)"); + + const char* contentChars = content.c_str(); + while (fileMatchRegex.find(contentChars)) { + std::string const qrcEntry = fileMatchRegex.match(1); + contentChars += qrcEntry.size(); + { + fileReplaceRegex.find(qrcEntry); + std::string const tag = fileReplaceRegex.match(1); + files.push_back(qrcEntry.substr(tag.size())); } - } else { - if (errorMessage != nullptr) { - std::ostringstream ost; - ost << "rcc file does not exist:\n" - << " " << cmQtAutoGen::Quoted(fileName) << "\n"; - *errorMessage = ost.str(); + } +} + +bool cmQtAutoGen::RccListParseOutput(std::string const& rccStdOut, + std::string const& rccStdErr, + std::vector<std::string>& files, + std::string& error) +{ + // 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)) { + StripCR(oline); + if (!oline.empty()) { + files.push_back(oline); + } + } + } + // Parse rcc error output + { + std::istringstream estr(rccStdErr); + std::string eline; + while (std::getline(estr, eline)) { + StripCR(eline); + if (cmHasLiteralPrefix(eline, "RCC: Error in")) { + static std::string const searchString = "Cannot find file '"; + + std::string::size_type pos = eline.find(searchString); + if (pos == std::string::npos) { + error = "rcc lists unparsable output:\n"; + error += cmQtAutoGen::Quoted(eline); + error += "\n"; + return false; + } + pos += searchString.length(); + std::string::size_type sz = eline.size() - pos - 1; + files.push_back(eline.substr(pos, sz)); + } + } + } + + return true; +} + +void cmQtAutoGen::RccListConvertFullPath(std::string const& qrcFileDir, + std::vector<std::string>& files) +{ + for (std::string& entry : files) { + std::string tmp = cmSystemTools::CollapseCombinedPath(qrcFileDir, entry); + entry = std::move(tmp); } - return allGood; } diff --git a/Source/cmQtAutoGen.h b/Source/cmQtAutoGen.h index acc092f..67f61b1 100644 --- a/Source/cmQtAutoGen.h +++ b/Source/cmQtAutoGen.h @@ -9,14 +9,18 @@ #include <vector> /** \class cmQtAutoGen - * \brief Class used as namespace for QtAutogen related types and functions + * \brief Common base class for QtAutoGen classes */ class cmQtAutoGen { public: - static std::string const listSep; + /// @brief Nested lists separator + static std::string const ListSep; + /// @brief Maximum number of parallel threads/processes in a generator + static unsigned int const ParallelMax; - enum Generator + /// @brief AutoGen generator type + enum class GeneratorT { GEN, // General MOC, @@ -24,27 +28,20 @@ public: RCC }; - enum MultiConfig - { - SINGLE, // Single configuration - WRAP, // Multi configuration using wrapper files - FULL // Full multi configuration using per config sources - }; - public: /// @brief Returns the generator name - static std::string const& GeneratorName(Generator genType); + static std::string const& GeneratorName(GeneratorT genType); /// @brief Returns the generator name in upper case - static std::string GeneratorNameUpper(Generator genType); - - /// @brief Returns the multi configuration name string - static std::string const& MultiConfigName(MultiConfig config); - /// @brief Returns the multi configuration type - static MultiConfig MultiConfigType(std::string const& name); + static std::string GeneratorNameUpper(GeneratorT genType); /// @brief Returns a the string escaped and enclosed in quotes static std::string Quoted(std::string const& text); + static std::string QuotedCommand(std::vector<std::string> const& command); + + /// @brief Returns the parent directory of the file with a "/" suffix + static std::string SubDirPrefix(std::string const& filename); + /// @brief Appends the suffix to the filename before the last dot static std::string AppendFilenameSuffix(std::string const& filename, std::string const& suffix); @@ -59,14 +56,21 @@ public: std::vector<std::string> const& newOpts, bool isQt5); - /// @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, - std::string const& fileName, - std::vector<std::string>& files, - std::string* errorMessage = nullptr); + /// @brief Parses the content of a qrc file + /// + /// Use when rcc does not support the "--list" option + static void RccListParseContent(std::string const& content, + std::vector<std::string>& files); + + /// @brief Parses the output of the "rcc --list ..." command + static bool RccListParseOutput(std::string const& rccStdOut, + std::string const& rccStdErr, + std::vector<std::string>& files, + std::string& error); + + /// @brief Converts relative qrc entry paths to full paths + static void RccListConvertFullPath(std::string const& qrcFileDir, + std::vector<std::string>& files); }; #endif 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/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx new file mode 100644 index 0000000..93c78b5 --- /dev/null +++ b/Source/cmQtAutoGenInitializer.cxx @@ -0,0 +1,1393 @@ +/* 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 "cmQtAutoGenInitializer.h" + +#include "cmAlgorithms.h" +#include "cmCustomCommand.h" +#include "cmCustomCommandLines.h" +#include "cmDuration.h" +#include "cmFilePathChecksum.h" +#include "cmGeneratedFileStream.h" +#include "cmGeneratorTarget.h" +#include "cmGlobalGenerator.h" +#include "cmLinkItem.h" +#include "cmLocalGenerator.h" +#include "cmMakefile.h" +#include "cmOutputConverter.h" +#include "cmPolicies.h" +#include "cmProcessOutput.h" +#include "cmSourceFile.h" +#include "cmSourceGroup.h" +#include "cmState.h" +#include "cmStateTypes.h" +#include "cmSystemTools.h" +#include "cmTarget.h" +#include "cmake.h" +#include "cmsys/FStream.hxx" +#include "cmsys/SystemInformation.hxx" + +#include <algorithm> +#include <array> +#include <deque> +#include <map> +#include <set> +#include <sstream> +#include <string> +#include <utility> +#include <vector> + +inline static const char* SafeString(const char* value) +{ + return (value != nullptr) ? value : ""; +} + +inline static std::string GetSafeProperty(cmGeneratorTarget const* target, + const char* key) +{ + return std::string(SafeString(target->GetProperty(key))); +} + +inline static std::string GetSafeProperty(cmSourceFile const* sf, + const char* key) +{ + return std::string(SafeString(sf->GetProperty(key))); +} + +static std::size_t GetParallelCPUCount() +{ + static std::size_t count = 0; + // Detect only on the first call + if (count == 0) { + cmsys::SystemInformation info; + info.RunCPUCheck(); + count = info.GetNumberOfPhysicalCPU(); + count = std::max<std::size_t>(count, 1); + count = std::min<std::size_t>(count, cmQtAutoGen::ParallelMax); + } + return count; +} + +static bool AddToSourceGroup(cmMakefile* makefile, std::string const& fileName, + cmQtAutoGen::GeneratorT genType) +{ + cmSourceGroup* sourceGroup = nullptr; + // Acquire source group + { + std::string property; + std::string groupName; + { + std::array<std::string, 2> props; + // Use generator specific group name + switch (genType) { + case cmQtAutoGen::GeneratorT::MOC: + props[0] = "AUTOMOC_SOURCE_GROUP"; + break; + case cmQtAutoGen::GeneratorT::RCC: + props[0] = "AUTORCC_SOURCE_GROUP"; + break; + default: + props[0] = "AUTOGEN_SOURCE_GROUP"; + break; + } + props[1] = "AUTOGEN_SOURCE_GROUP"; + for (std::string& prop : props) { + const char* propName = makefile->GetState()->GetGlobalProperty(prop); + if ((propName != nullptr) && (*propName != '\0')) { + groupName = propName; + property = std::move(prop); + break; + } + } + } + // Generate a source group on demand + if (!groupName.empty()) { + sourceGroup = makefile->GetOrCreateSourceGroup(groupName); + if (sourceGroup == nullptr) { + std::ostringstream ost; + ost << cmQtAutoGen::GeneratorNameUpper(genType); + ost << ": " << property; + ost << ": Could not find or create the source group "; + ost << cmQtAutoGen::Quoted(groupName); + cmSystemTools::Error(ost.str().c_str()); + return false; + } + } + } + if (sourceGroup != nullptr) { + sourceGroup->AddGroupFile(fileName); + } + return true; +} + +static void AddCleanFile(cmMakefile* makefile, std::string const& fileName) +{ + makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", fileName.c_str(), + false); +} + +static std::string FileProjectRelativePath(cmMakefile* makefile, + std::string const& fileName) +{ + std::string res; + { + std::string pSource = cmSystemTools::RelativePath( + makefile->GetCurrentSourceDirectory(), fileName); + std::string pBinary = cmSystemTools::RelativePath( + makefile->GetCurrentBinaryDirectory(), fileName); + if (pSource.size() < pBinary.size()) { + res = std::move(pSource); + } else if (pBinary.size() < fileName.size()) { + res = std::move(pBinary); + } else { + res = fileName; + } + } + return res; +} + +/* @brief Tests if targetDepend is a STATIC_LIBRARY and if any of its + * recursive STATIC_LIBRARY dependencies depends on targetOrigin + * (STATIC_LIBRARY cycle). + */ +static bool StaticLibraryCycle(cmGeneratorTarget const* targetOrigin, + cmGeneratorTarget const* targetDepend, + std::string const& config) +{ + bool cycle = false; + if ((targetOrigin->GetType() == cmStateEnums::STATIC_LIBRARY) && + (targetDepend->GetType() == cmStateEnums::STATIC_LIBRARY)) { + std::set<cmGeneratorTarget const*> knownLibs; + std::deque<cmGeneratorTarget const*> testLibs; + + // Insert initial static_library dependency + knownLibs.insert(targetDepend); + testLibs.push_back(targetDepend); + + while (!testLibs.empty()) { + cmGeneratorTarget const* testTarget = testLibs.front(); + testLibs.pop_front(); + // Check if the test target is the origin target (cycle) + if (testTarget == targetOrigin) { + cycle = true; + break; + } + // Collect all static_library dependencies from the test target + cmLinkImplementationLibraries const* libs = + testTarget->GetLinkImplementationLibraries(config); + if (libs != nullptr) { + for (cmLinkItem const& item : libs->Libraries) { + cmGeneratorTarget const* depTarget = item.Target; + if ((depTarget != nullptr) && + (depTarget->GetType() == cmStateEnums::STATIC_LIBRARY) && + knownLibs.insert(depTarget).second) { + testLibs.push_back(depTarget); + } + } + } + } + } + return cycle; +} + +cmQtAutoGenInitializer::cmQtAutoGenInitializer( + cmGeneratorTarget* target, bool mocEnabled, bool uicEnabled, bool rccEnabled, + std::string const& qtVersionMajor) + : Target(target) + , MocEnabled(mocEnabled) + , UicEnabled(uicEnabled) + , RccEnabled(rccEnabled) + , MultiConfig(false) + , QtVersionMajor(qtVersionMajor) +{ + this->QtVersionMinor = + cmQtAutoGenInitializer::GetQtMinorVersion(target, this->QtVersionMajor); +} + +void cmQtAutoGenInitializer::InitCustomTargets() +{ + cmMakefile* makefile = this->Target->Target->GetMakefile(); + cmLocalGenerator* localGen = this->Target->GetLocalGenerator(); + cmGlobalGenerator* globalGen = localGen->GetGlobalGenerator(); + + // Configurations + this->MultiConfig = globalGen->IsMultiConfig(); + this->ConfigDefault = makefile->GetConfigurations(this->ConfigsList); + if (this->ConfigsList.empty()) { + this->ConfigsList.push_back(this->ConfigDefault); + } + + // Autogen target name + this->AutogenTargetName = this->Target->GetName(); + this->AutogenTargetName += "_autogen"; + + // Autogen directories + { + // 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; + } + cmSystemTools::ConvertToUnixSlashes(this->DirBuild); + + // Working directory + this->DirWork = cbd; + cmSystemTools::ConvertToUnixSlashes(this->DirWork); + } + + // Autogen files + { + this->AutogenInfoFile = this->DirInfo; + this->AutogenInfoFile += "/AutogenInfo.cmake"; + + this->AutogenSettingsFile = this->DirInfo; + this->AutogenSettingsFile += "/AutogenOldSettings.txt"; + } + + // Autogen target FOLDER property + { + const char* folder = + makefile->GetState()->GetGlobalProperty("AUTOMOC_TARGETS_FOLDER"); + if (folder == nullptr) { + folder = + makefile->GetState()->GetGlobalProperty("AUTOGEN_TARGETS_FOLDER"); + } + // Inherit FOLDER property from target (#13688) + if (folder == nullptr) { + folder = SafeString(this->Target->Target->GetProperty("FOLDER")); + } + if (folder != nullptr) { + this->AutogenFolder = folder; + } + } + + std::set<std::string> autogenDependFiles; + std::set<cmTarget*> autogenDependTargets; + std::vector<std::string> autogenProvides; + + // Remove build directories on cleanup + AddCleanFile(makefile, this->DirBuild); + // Remove old settings on cleanup + { + std::string base = this->DirInfo; + base += "/AutogenOldSettings"; + if (this->MultiConfig) { + for (std::string const& cfg : this->ConfigsList) { + std::string filename = base; + filename += '_'; + filename += cfg; + filename += ".cmake"; + AddCleanFile(makefile, filename); + } + } else { + AddCleanFile(makefile, base.append(".cmake")); + } + } + + // Add moc compilation to generated files list + if (this->MocEnabled) { + std::string mocsComp = this->DirBuild + "/mocs_compilation.cpp"; + this->AddGeneratedSource(mocsComp, GeneratorT::MOC); + autogenProvides.push_back(std::move(mocsComp)); + } + + // Add autogen includes directory to the origin target INCLUDE_DIRECTORIES + if (this->MocEnabled || this->UicEnabled || + (this->RccEnabled && this->MultiConfig)) { + std::string includeDir = this->DirBuild; + includeDir += "/include"; + if (this->MultiConfig) { + includeDir += "_$<CONFIG>"; + } + 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, cmDuration::zero(), 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 + std::vector<std::string> generatedSources; + std::vector<std::string> generatedHeaders; + { + std::string const qrcExt = "qrc"; + std::vector<cmSourceFile*> srcFiles; + this->Target->GetConfigCommonSourceFiles(srcFiles); + for (cmSourceFile* sf : srcFiles) { + if (sf->GetPropertyAsBool("SKIP_AUTOGEN")) { + continue; + } + // sf->GetExtension() is only valid after sf->GetFullPath() ... + std::string const& fPath = sf->GetFullPath(); + std::string const& ext = sf->GetExtension(); + // Register generated files that will be scanned by moc or uic + 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 ((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 { + this->Headers.push_back(absPath); + } + } else { + if (generated) { + generatedSources.push_back(absPath); + } else { + this->Sources.push_back(absPath); + } + } + } + } + } + // Register rcc enabled files + if (this->RccEnabled && (ext == qrcExt) && + !sf->GetPropertyAsBool("SKIP_AUTORCC")) { + // Register qrc file + { + 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, qrc.Options); + } + } + this->Qrcs.push_back(std::move(qrc)); + } + } + } + // cmGeneratorTarget::GetConfigCommonSourceFiles computes the target's + // 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. + this->Target->ClearSourcesCache(); + } + // Read skip files from makefile sources + if (this->MocEnabled || this->UicEnabled) { + std::string pathError; + for (cmSourceFile* sf : makefile->GetSourceFiles()) { + // sf->GetExtension() is only valid after sf->GetFullPath() ... + // Since we're iterating over source files that might be not in the + // target we need to check for path errors (not existing files). + std::string const& fPath = sf->GetFullPath(&pathError); + if (!pathError.empty()) { + pathError.clear(); + continue; + } + 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 + if (!generatedSources.empty() || !generatedHeaders.empty()) { + // Check status of policy CMP0071 + bool policyAccept = false; + bool policyWarn = false; + cmPolicies::PolicyStatus const CMP0071_status = + makefile->GetPolicyStatus(cmPolicies::CMP0071); + switch (CMP0071_status) { + case cmPolicies::WARN: + policyWarn = true; + CM_FALLTHROUGH; + case cmPolicies::OLD: + // Ignore GENERATED file + break; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + // Process GENERATED file + policyAccept = true; + break; + } + + if (policyAccept) { + // Accept GENERATED sources + for (std::string const& absFile : generatedHeaders) { + this->Headers.push_back(absFile); + autogenDependFiles.insert(absFile); + } + for (std::string const& absFile : generatedSources) { + this->Sources.push_back(absFile); + autogenDependFiles.insert(absFile); + } + } else { + if (policyWarn) { + std::string msg; + msg += cmPolicies::GetPolicyWarning(cmPolicies::CMP0071); + msg += "\n"; + std::string tools; + std::string property; + if (this->MocEnabled && this->UicEnabled) { + tools = "AUTOMOC and AUTOUIC"; + property = "SKIP_AUTOGEN"; + } else if (this->MocEnabled) { + tools = "AUTOMOC"; + property = "SKIP_AUTOMOC"; + } else if (this->UicEnabled) { + tools = "AUTOUIC"; + property = "SKIP_AUTOUIC"; + } + msg += "For compatibility, CMake is excluding the GENERATED source " + "file(s):\n"; + for (const std::string& absFile : generatedHeaders) { + msg.append(" ").append(Quoted(absFile)).append("\n"); + } + for (const std::string& absFile : generatedSources) { + msg.append(" ").append(Quoted(absFile)).append("\n"); + } + msg += "from processing by "; + msg += tools; + msg += + ". If any of the files should be processed, set CMP0071 to NEW. " + "If any of the files should not be processed, " + "explicitly exclude them by setting the source file property "; + msg += property; + msg += ":\n set_property(SOURCE file.h PROPERTY "; + msg += property; + msg += " ON)\n"; + makefile->IssueMessage(cmake::AUTHOR_WARNING, msg); + } + } + // Clear lists + generatedSources.clear(); + generatedHeaders.clear(); + } + // Sort headers and sources + 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 (!this->Qrcs.empty()) { + const bool QtV5 = (this->QtVersionMajor == "5"); + // Target rcc options + std::vector<std::string> optionsTarget; + cmSystemTools::ExpandListArgument( + GetSafeProperty(this->Target, "AUTORCC_OPTIONS"), optionsTarget); + + // Check if file name is unique + 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 and file names + { + cmFilePathChecksum const fpathCheckSum(makefile); + for (Qrc& qrc : this->Qrcs) { + qrc.PathChecksum = fpathCheckSum.getPart(qrc.QrcFile); + // RCC output file name + { + 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.txt"; + } + } + } + // RCC options + for (Qrc& qrc : this->Qrcs) { + // Target options + std::vector<std::string> opts = optionsTarget; + // Merge computed "-name XYZ" option + { + std::string name = qrc.QrcName; + // Replace '-' with '_'. The former is not valid for symbol names. + std::replace(name.begin(), name.end(), '-', '_'); + if (!qrc.Unique) { + name += "_"; + name += qrc.PathChecksum; + } + std::vector<std::string> nameOpts; + nameOpts.emplace_back("-name"); + nameOpts.emplace_back(std::move(name)); + RccMergeOptions(opts, nameOpts, QtV5); + } + // Merge file option + RccMergeOptions(opts, qrc.Options, QtV5); + qrc.Options = std::move(opts); + } + for (Qrc& qrc : this->Qrcs) { + // Register file at target + this->AddGeneratedSource(qrc.RccFile, GeneratorT::RCC); + + std::vector<std::string> ccOutput; + ccOutput.push_back(qrc.RccFile); + cmCustomCommandLines commandLines; + { + 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)); + } + 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 and info file to the custom target dependencies + ccDepends.push_back(qrc.QrcFile); + ccDepends.push_back(qrc.InfoFile); + + 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 { + // Create custom rcc command + { + std::vector<std::string> ccByproducts; + std::vector<std::string> ccDepends; + // Add the .qrc and info file to the custom command dependencies + ccDepends.push_back(qrc.QrcFile); + ccDepends.push_back(qrc.InfoFile); + + // Add the resource files to the dependencies + { + std::string error; + if (RccListInputs(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()); + } + } + makefile->AddCustomCommandToOutput(ccOutput, ccByproducts, ccDepends, + /*main_dependency*/ std::string(), + commandLines, ccComment.c_str(), + this->DirWork.c_str()); + } + // Reconfigure when .qrc file changes + makefile->AddCMakeDependFile(qrc.QrcFile); + } + } + } + + // 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); + } + } + } + } + + // 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(); + } + + // 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)); + } + + // 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); + } + + // 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 + { + // add_dependencies/addUtility do not support generator expressions. + // We depend only on the libraries found in all configs therefore. + std::map<cmGeneratorTarget const*, std::size_t> commonTargets; + 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)) { + // Increment target config count + commonTargets[libTarget]++; + } + } + } + } + for (auto const& item : commonTargets) { + if (item.second == this->ConfigsList.size()) { + autogenDependTargets.insert(item.first->Target); + } + } + } + + // Create autogen target + cmTarget* autogenTarget = makefile->AddUtilityCommand( + this->AutogenTargetName, cmMakefile::TargetOrigin::Generator, true, + this->DirWork.c_str(), /*byproducts=*/autogenProvides, + std::vector<std::string>(autogenDependFiles.begin(), + autogenDependFiles.end()), + 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); + } + // Add additional autogen target dependencies to autogen target + for (cmTarget* depTarget : autogenDependTargets) { + autogenTarget->AddUtility(depTarget->GetName(), makefile); + } + + // 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 + this->Target->Target->AddUtility(this->AutogenTargetName, makefile); + } + } +} + +void cmQtAutoGenInitializer::SetupCustomTargets() +{ + cmMakefile* makefile = this->Target->Target->GetMakefile(); + + // Create info directory on demand + if (!cmSystemTools::MakeDirectory(this->DirInfo)) { + std::string emsg = ("Could not create directory: "); + emsg += Quoted(this->DirInfo); + cmSystemTools::Error(emsg.c_str()); + } + + // Configuration include directories + std::string includeDir = "include"; + std::map<std::string, std::string> includeDirs; + for (std::string const& cfg : this->ConfigsList) { + std::string& dir = includeDirs[cfg]; + dir = "include_"; + dir += cfg; + } + + // Generate autogen target info file + if (this->MocEnabled || this->UicEnabled) { + if (this->MocEnabled) { + this->SetupCustomTargetsMoc(); + } + if (this->UicEnabled) { + this->SetupCustomTargetsUic(); + } + + // Parallel processing + this->Parallel = GetSafeProperty(this->Target, "AUTOGEN_PARALLEL"); + if (this->Parallel.empty() || (this->Parallel == "AUTO")) { + // Autodetect number of CPUs + this->Parallel = std::to_string(GetParallelCPUCount()); + } + + cmGeneratedFileStream ofs; + ofs.SetCopyIfDifferent(true); + ofs.Open(this->AutogenInfoFile.c_str(), false, true); + if (ofs) { + // Utility lambdas + auto CWrite = [&ofs](const char* key, std::string const& value) { + ofs << "set(" << key << " " << cmOutputConverter::EscapeForCMake(value) + << ")\n"; + }; + auto CWriteList = [&CWrite](const char* key, + std::vector<std::string> const& list) { + CWrite(key, cmJoin(list, ";")); + }; + auto CWriteNestedLists = [&CWrite]( + const char* key, std::vector<std::vector<std::string>> const& lists) { + std::vector<std::string> seplist; + for (const std::vector<std::string>& list : lists) { + std::string blist = "{"; + blist += cmJoin(list, ";"); + blist += "}"; + seplist.push_back(std::move(blist)); + } + CWrite(key, cmJoin(seplist, cmQtAutoGen::ListSep)); + }; + auto CWriteSet = [&CWrite](const char* key, + std::set<std::string> const& list) { + CWrite(key, cmJoin(list, ";")); + }; + auto CWriteMap = [&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"; + } + }; + auto MfDef = [makefile](const char* key) { + return std::string(makefile->GetSafeDefinition(key)); + }; + + // Write + ofs << "# Meta\n"; + CWrite("AM_MULTI_CONFIG", this->MultiConfig ? "TRUE" : "FALSE"); + CWrite("AM_PARALLEL", this->Parallel); + + ofs << "# Directories\n"; + CWrite("AM_CMAKE_SOURCE_DIR", MfDef("CMAKE_SOURCE_DIR")); + CWrite("AM_CMAKE_BINARY_DIR", MfDef("CMAKE_BINARY_DIR")); + CWrite("AM_CMAKE_CURRENT_SOURCE_DIR", MfDef("CMAKE_CURRENT_SOURCE_DIR")); + CWrite("AM_CMAKE_CURRENT_BINARY_DIR", MfDef("CMAKE_CURRENT_BINARY_DIR")); + CWrite("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE", + MfDef("CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE")); + CWrite("AM_BUILD_DIR", this->DirBuild); + if (this->MultiConfig) { + CWriteMap("AM_INCLUDE_DIR", includeDirs); + } else { + CWrite("AM_INCLUDE_DIR", includeDir); + } + + ofs << "# Files\n"; + CWriteList("AM_SOURCES", this->Sources); + CWriteList("AM_HEADERS", this->Headers); + if (this->MultiConfig) { + std::map<std::string, std::string> settingsFiles; + for (std::string const& cfg : this->ConfigsList) { + settingsFiles[cfg] = + AppendFilenameSuffix(this->AutogenSettingsFile, "_" + cfg); + } + CWriteMap("AM_SETTINGS_FILE", settingsFiles); + } else { + CWrite("AM_SETTINGS_FILE", this->AutogenSettingsFile); + } + + ofs << "# Qt\n"; + CWrite("AM_QT_VERSION_MAJOR", this->QtVersionMajor); + CWrite("AM_QT_MOC_EXECUTABLE", this->MocExecutable); + CWrite("AM_QT_UIC_EXECUTABLE", this->UicExecutable); + + if (this->MocEnabled) { + ofs << "# MOC settings\n"; + CWriteSet("AM_MOC_SKIP", this->MocSkip); + CWrite("AM_MOC_DEFINITIONS", this->MocDefines); + CWriteMap("AM_MOC_DEFINITIONS", this->MocDefinesConfig); + CWrite("AM_MOC_INCLUDES", this->MocIncludes); + CWriteMap("AM_MOC_INCLUDES", this->MocIncludesConfig); + CWrite("AM_MOC_OPTIONS", + GetSafeProperty(this->Target, "AUTOMOC_MOC_OPTIONS")); + CWrite("AM_MOC_RELAXED_MODE", MfDef("CMAKE_AUTOMOC_RELAXED_MODE")); + CWrite("AM_MOC_MACRO_NAMES", + GetSafeProperty(this->Target, "AUTOMOC_MACRO_NAMES")); + CWrite("AM_MOC_DEPEND_FILTERS", + GetSafeProperty(this->Target, "AUTOMOC_DEPEND_FILTERS")); + CWrite("AM_MOC_PREDEFS_CMD", this->MocPredefsCmd); + } + + if (this->UicEnabled) { + ofs << "# UIC settings\n"; + CWriteSet("AM_UIC_SKIP", this->UicSkip); + CWrite("AM_UIC_TARGET_OPTIONS", this->UicOptions); + CWriteMap("AM_UIC_TARGET_OPTIONS", this->UicOptionsConfig); + CWriteList("AM_UIC_OPTIONS_FILES", this->UicFileFiles); + CWriteNestedLists("AM_UIC_OPTIONS_OPTIONS", this->UicFileOptions); + CWriteList("AM_UIC_SEARCH_PATHS", this->UicSearchPaths); + } + } else { + return; + } + } + + // Generate auto RCC info files + if (this->RccEnabled) { + for (Qrc const& qrc : this->Qrcs) { + cmGeneratedFileStream ofs; + ofs.SetCopyIfDifferent(true); + ofs.Open(qrc.InfoFile.c_str(), false, true); + if (ofs) { + // Utility lambdas + auto CWrite = [&ofs](const char* key, std::string const& value) { + ofs << "set(" << key << " " + << cmOutputConverter::EscapeForCMake(value) << ")\n"; + }; + auto CWriteMap = [&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"; + } + }; + + // Write + ofs << "# Configurations\n"; + CWrite("ARCC_MULTI_CONFIG", this->MultiConfig ? "TRUE" : "FALSE"); + + ofs << "# Settings file\n"; + if (this->MultiConfig) { + std::map<std::string, std::string> settingsFiles; + for (std::string const& cfg : this->ConfigsList) { + settingsFiles[cfg] = + AppendFilenameSuffix(qrc.SettingsFile, "_" + cfg); + } + CWriteMap("ARCC_SETTINGS_FILE", settingsFiles); + } else { + CWrite("ARCC_SETTINGS_FILE", qrc.SettingsFile); + } + + ofs << "# Directories\n"; + CWrite("ARCC_BUILD_DIR", this->DirBuild); + if (this->MultiConfig) { + CWriteMap("ARCC_INCLUDE_DIR", includeDirs); + } else { + CWrite("ARCC_INCLUDE_DIR", includeDir); + } + + ofs << "# Rcc executable\n"; + CWrite("ARCC_RCC_EXECUTABLE", this->RccExecutable); + CWrite("ARCC_RCC_LIST_OPTIONS", cmJoin(this->RccListOptions, ";")); + + ofs << "# Rcc job\n"; + CWrite("ARCC_SOURCE", qrc.QrcFile); + CWrite("ARCC_OUTPUT_CHECKSUM", qrc.PathChecksum); + CWrite("ARCC_OUTPUT_NAME", + cmSystemTools::GetFilenameName(qrc.RccFile)); + CWrite("ARCC_OPTIONS", cmJoin(qrc.Options, ";")); + CWrite("ARCC_INPUTS", cmJoin(qrc.Resources, ";")); + } else { + return; + } + } + } +} + +void cmQtAutoGenInitializer::SetupCustomTargetsMoc() +{ + cmLocalGenerator* localGen = this->Target->GetLocalGenerator(); + cmMakefile* makefile = this->Target->Target->GetMakefile(); + + // Moc predefs command + if (this->Target->GetPropertyAsBool("AUTOMOC_COMPILER_PREDEFINES") && + this->QtVersionGreaterOrEqual(5, 8)) { + this->MocPredefsCmd = + 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 + this->MocIncludes = GetIncludeDirs(this->ConfigDefault); + this->MocDefines = GetCompileDefinitions(this->ConfigDefault); + // Other configuration settings + for (std::string const& cfg : this->ConfigsList) { + { + std::string const configIncludeDirs = GetIncludeDirs(cfg); + if (configIncludeDirs != this->MocIncludes) { + this->MocIncludesConfig[cfg] = configIncludeDirs; + } + } + { + std::string const configCompileDefs = GetCompileDefinitions(cfg); + if (configCompileDefs != this->MocDefines) { + this->MocDefinesConfig[cfg] = configCompileDefs; + } + } + } + } + + // 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 { + err = "The AUTOMOC feature supports only Qt 4 and Qt 5"; + } + + if (err.empty()) { + this->MocExecutable = mocExec; + } else { + err += " ("; + err += this->Target->GetName(); + err += ")"; + cmSystemTools::Error(err.c_str()); + } + } +} + +void cmQtAutoGenInitializer::SetupCustomTargetsUic() +{ + cmMakefile* makefile = this->Target->Target->GetMakefile(); + + // Uic search paths + { + std::string const usp = + GetSafeProperty(this->Target, "AUTOUIC_SEARCH_PATHS"); + if (!usp.empty()) { + cmSystemTools::ExpandListArgument(usp, this->UicSearchPaths); + std::string const srcDir = makefile->GetCurrentSourceDirectory(); + for (std::string& path : this->UicSearchPaths) { + path = cmSystemTools::CollapseFullPath(path, srcDir); + } + } + } + // 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 + this->UicOptions = UicGetOpts(this->ConfigDefault); + + // Configuration specific settings + for (std::string const& cfg : this->ConfigsList) { + std::string const configUicOpts = UicGetOpts(cfg); + if (configUicOpts != this->UicOptions) { + this->UicOptionsConfig[cfg] = configUicOpts; + } + } + } + // .ui files skip and options + { + std::string const uiExt = "ui"; + std::string pathError; + for (cmSourceFile* sf : makefile->GetSourceFiles()) { + // sf->GetExtension() is only valid after sf->GetFullPath() ... + // Since we're iterating over source files that might be not in the + // target we need to check for path errors (not existing files). + std::string const& fPath = sf->GetFullPath(&pathError); + if (!pathError.empty()) { + pathError.clear(); + continue; + } + 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) { + this->UicFileFiles.push_back(absFile); + std::vector<std::string> optsVec; + cmSystemTools::ExpandListArgument(uicOpts, optsVec); + this->UicFileOptions.push_back(std::move(optsVec)); + } + } + } + } + } + + // 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()) { + this->UicExecutable = uicExec; + } else { + err += " ("; + err += this->Target->GetName(); + err += ")"; + cmSystemTools::Error(err.c_str()); + } + } +} + +void cmQtAutoGenInitializer::AddGeneratedSource(std::string const& filename, + GeneratorT genType) +{ + // Register source file in makefile + cmMakefile* makefile = this->Target->Target->GetMakefile(); + { + cmSourceFile* gFile = makefile->GetOrCreateSource(filename, true); + gFile->SetProperty("GENERATED", "1"); + gFile->SetProperty("SKIP_AUTOGEN", "On"); + } + + // Add source file to source group + AddToSourceGroup(makefile, filename, genType); + + // Add source file to target + this->Target->AddSource(filename); +} + +std::string cmQtAutoGenInitializer::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 cmQtAutoGenInitializer::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 cmQtAutoGenInitializer::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; +} + +/// @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 read +bool cmQtAutoGenInitializer::RccListInputs(std::string const& fileName, + std::vector<std::string>& files, + std::string& error) +{ + if (!cmSystemTools::FileExists(fileName)) { + error = "rcc resource file does not exist:\n "; + error += Quoted(fileName); + error += "\n"; + return false; + } + if (!RccListOptions.empty()) { + // Use rcc for file listing + if (RccExecutable.empty()) { + error = "rcc executable not available"; + return false; + } + + // Run rcc list command in the directory of the qrc file with the + // pathless + // qrc file name argument. This way rcc prints relative paths. + // This avoids issues on Windows when the qrc file is in a path that + // contains non-ASCII characters. + std::string const fileDir = cmSystemTools::GetFilenamePath(fileName); + std::string const fileNameName = cmSystemTools::GetFilenameName(fileName); + + bool result = false; + int retVal = 0; + std::string rccStdOut; + std::string rccStdErr; + { + std::vector<std::string> cmd; + cmd.push_back(RccExecutable); + cmd.insert(cmd.end(), RccListOptions.begin(), RccListOptions.end()); + cmd.push_back(fileNameName); + result = cmSystemTools::RunSingleCommand( + cmd, &rccStdOut, &rccStdErr, &retVal, fileDir.c_str(), + cmSystemTools::OUTPUT_NONE, cmDuration::zero(), cmProcessOutput::Auto); + } + if (!result || retVal) { + error = "rcc list process failed for:\n "; + error += Quoted(fileName); + error += "\n"; + error += rccStdOut; + error += "\n"; + error += rccStdErr; + error += "\n"; + return false; + } + if (!RccListParseOutput(rccStdOut, rccStdErr, files, error)) { + return false; + } + } else { + // We can't use rcc for the file listing. + // Read the qrc file content into string and parse it. + { + std::string qrcContents; + { + cmsys::ifstream ifs(fileName.c_str()); + if (ifs) { + std::ostringstream osst; + osst << ifs.rdbuf(); + qrcContents = osst.str(); + } else { + error = "rcc file not readable:\n "; + error += Quoted(fileName); + error += "\n"; + return false; + } + } + // Parse string content + RccListParseContent(qrcContents, files); + } + } + + // Convert relative paths to absolute paths + RccListConvertFullPath(cmSystemTools::GetFilenamePath(fileName), files); + return true; +} diff --git a/Source/cmQtAutoGenInitializer.h b/Source/cmQtAutoGenInitializer.h new file mode 100644 index 0000000..2a47e46 --- /dev/null +++ b/Source/cmQtAutoGenInitializer.h @@ -0,0 +1,115 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmQtAutoGenInitializer_h +#define cmQtAutoGenInitializer_h + +#include "cmConfigure.h" // IWYU pragma: keep +#include "cmQtAutoGen.h" + +#include <map> +#include <set> +#include <string> +#include <vector> + +class cmGeneratorTarget; + +/// @brief Initializes the QtAutoGen generators +class cmQtAutoGenInitializer : public cmQtAutoGen +{ +public: + static std::string GetQtMajorVersion(cmGeneratorTarget const* target); + static std::string GetQtMinorVersion(cmGeneratorTarget const* target, + std::string const& qtVersionMajor); + + /// @brief Rcc job information + 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: + cmQtAutoGenInitializer(cmGeneratorTarget* target, bool mocEnabled, + bool uicEnabled, bool rccEnabled, + std::string const& qtVersionMajor); + + void InitCustomTargets(); + void SetupCustomTargets(); + +private: + void SetupCustomTargetsMoc(); + void SetupCustomTargetsUic(); + + void AddGeneratedSource(std::string const& filename, GeneratorT genType); + + bool QtVersionGreaterOrEqual(unsigned long requestMajor, + unsigned long requestMinor) const; + + bool RccListInputs(std::string const& fileName, + std::vector<std::string>& files, + std::string& errorMessage); + +private: + cmGeneratorTarget* Target; + bool MocEnabled; + bool UicEnabled; + bool RccEnabled; + bool MultiConfig; + // Qt + std::string QtVersionMajor; + std::string QtVersionMinor; + std::string MocExecutable; + std::string UicExecutable; + std::string RccExecutable; + std::vector<std::string> RccListOptions; + // Configurations + std::string ConfigDefault; + std::vector<std::string> ConfigsList; + std::string Parallel; + // 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; + // Moc + std::string MocPredefsCmd; + std::set<std::string> MocSkip; + std::string MocIncludes; + std::map<std::string, std::string> MocIncludesConfig; + std::string MocDefines; + std::map<std::string, std::string> MocDefinesConfig; + // Uic + std::set<std::string> UicSkip; + std::vector<std::string> UicSearchPaths; + std::string UicOptions; + std::map<std::string, std::string> UicOptionsConfig; + std::vector<std::string> UicFileFiles; + std::vector<std::vector<std::string>> UicFileOptions; + // Rcc + std::vector<Qrc> Qrcs; +}; + +#endif diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx new file mode 100644 index 0000000..1939bd4 --- /dev/null +++ b/Source/cmQtAutoGenerator.cxx @@ -0,0 +1,641 @@ +/* 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 "cmAlgorithms.h" +#include "cmGlobalGenerator.h" +#include "cmMakefile.h" +#include "cmStateDirectory.h" +#include "cmStateSnapshot.h" +#include "cmSystemTools.h" +#include "cmake.h" + +#include <algorithm> + +// -- Class methods + +void cmQtAutoGenerator::Logger::SetVerbose(bool value) +{ + Verbose_ = value; +} + +void cmQtAutoGenerator::Logger::SetColorOutput(bool value) +{ + ColorOutput_ = value; +} + +std::string cmQtAutoGenerator::Logger::HeadLine(std::string const& title) +{ + std::string head = title; + head += '\n'; + head.append(head.size() - 1, '-'); + head += '\n'; + return head; +} + +void cmQtAutoGenerator::Logger::Info(GeneratorT genType, + std::string const& message) +{ + std::string msg = GeneratorName(genType); + msg += ": "; + msg += message; + if (msg.back() != '\n') { + msg.push_back('\n'); + } + { + std::lock_guard<std::mutex> lock(Mutex_); + cmSystemTools::Stdout(msg.c_str(), msg.size()); + } +} + +void cmQtAutoGenerator::Logger::Warning(GeneratorT genType, + std::string const& message) +{ + std::string msg; + if (message.find('\n') == std::string::npos) { + // Single line message + msg += GeneratorName(genType); + msg += " warning: "; + } else { + // Multi line message + msg += HeadLine(GeneratorName(genType) + " warning"); + } + // Message + msg += message; + if (msg.back() != '\n') { + msg.push_back('\n'); + } + msg.push_back('\n'); + { + std::lock_guard<std::mutex> lock(Mutex_); + cmSystemTools::Stdout(msg.c_str(), msg.size()); + } +} + +void cmQtAutoGenerator::Logger::WarningFile(GeneratorT genType, + std::string const& filename, + std::string const& message) +{ + std::string msg = " "; + msg += Quoted(filename); + msg.push_back('\n'); + // Message + msg += message; + Warning(genType, msg); +} + +void cmQtAutoGenerator::Logger::Error(GeneratorT genType, + std::string const& message) +{ + std::string msg; + msg += HeadLine(GeneratorName(genType) + " error"); + // Message + msg += message; + if (msg.back() != '\n') { + msg.push_back('\n'); + } + msg.push_back('\n'); + { + std::lock_guard<std::mutex> lock(Mutex_); + cmSystemTools::Stderr(msg.c_str(), msg.size()); + } +} + +void cmQtAutoGenerator::Logger::ErrorFile(GeneratorT genType, + std::string const& filename, + std::string const& message) +{ + std::string emsg = " "; + emsg += Quoted(filename); + emsg += '\n'; + // Message + emsg += message; + Error(genType, emsg); +} + +void cmQtAutoGenerator::Logger::ErrorCommand( + GeneratorT genType, std::string const& message, + std::vector<std::string> const& command, std::string const& output) +{ + std::string msg; + msg.push_back('\n'); + msg += HeadLine(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'); + { + std::lock_guard<std::mutex> lock(Mutex_); + cmSystemTools::Stderr(msg.c_str(), msg.size()); + } +} + +std::string cmQtAutoGenerator::FileSystem::RealPath( + std::string const& filename) +{ + std::lock_guard<std::mutex> lock(Mutex_); + return cmSystemTools::GetRealPath(filename); +} + +bool cmQtAutoGenerator::FileSystem::FileExists(std::string const& filename) +{ + std::lock_guard<std::mutex> lock(Mutex_); + return cmSystemTools::FileExists(filename); +} + +bool cmQtAutoGenerator::FileSystem::FileIsOlderThan( + std::string const& buildFile, std::string const& sourceFile, + std::string* error) +{ + bool res(false); + int result = 0; + { + std::lock_guard<std::mutex> lock(Mutex_); + res = cmSystemTools::FileTimeCompare(buildFile, sourceFile, &result); + } + if (res) { + res = (result < 0); + } else { + if (error != nullptr) { + error->append( + "File modification time comparison failed for the files\n "); + error->append(Quoted(buildFile)); + error->append("\nand\n "); + error->append(Quoted(sourceFile)); + } + } + return res; +} + +bool cmQtAutoGenerator::FileSystem::FileRead(std::string& content, + std::string const& filename, + std::string* error) +{ + bool success = false; + { + std::lock_guard<std::mutex> lock(Mutex_); + if (cmSystemTools::FileExists(filename, true)) { + std::size_t const length = cmSystemTools::FileLength(filename); + cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary)); + if (ifs) { + if (length > 0) { + 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 { + // Readable but empty file + content.clear(); + success = true; + } + } else if (error != nullptr) { + error->append("Opening the file for reading failed."); + } + } else if (error != nullptr) { + error->append( + "The file does not exist, is not readable or is a directory."); + } + } + return success; +} + +bool cmQtAutoGenerator::FileSystem::FileRead(GeneratorT genType, + std::string& content, + std::string const& filename) +{ + std::string error; + if (!FileRead(content, filename, &error)) { + Log()->ErrorFile(genType, filename, error); + return false; + } + return true; +} + +bool cmQtAutoGenerator::FileSystem::FileWrite(std::string const& filename, + std::string const& content, + std::string* error) +{ + bool success = false; + // Make sure the parent directory exists + if (MakeParentDirectory(filename)) { + std::lock_guard<std::mutex> lock(Mutex_); + 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()) { + success = true; + } else { + if (error != nullptr) { + error->assign("File writing failed"); + } + } + } else { + if (error != nullptr) { + error->assign("Opening file for writing failed"); + } + } + } else { + if (error != nullptr) { + error->assign("Could not create parent directory"); + } + } + return success; +} + +bool cmQtAutoGenerator::FileSystem::FileWrite(GeneratorT genType, + std::string const& filename, + std::string const& content) +{ + std::string error; + if (!FileWrite(filename, content, &error)) { + Log()->ErrorFile(genType, filename, error); + return false; + } + return true; +} + +bool cmQtAutoGenerator::FileSystem::FileDiffers(std::string const& filename, + std::string const& content) +{ + bool differs = true; + { + std::string oldContents; + if (FileRead(oldContents, filename)) { + differs = (oldContents != content); + } + } + return differs; +} + +bool cmQtAutoGenerator::FileSystem::FileRemove(std::string const& filename) +{ + std::lock_guard<std::mutex> lock(Mutex_); + return cmSystemTools::RemoveFile(filename); +} + +bool cmQtAutoGenerator::FileSystem::Touch(std::string const& filename) +{ + std::lock_guard<std::mutex> lock(Mutex_); + return cmSystemTools::Touch(filename, false); +} + +bool cmQtAutoGenerator::FileSystem::MakeDirectory(std::string const& dirname) +{ + std::lock_guard<std::mutex> lock(Mutex_); + return cmSystemTools::MakeDirectory(dirname); +} + +bool cmQtAutoGenerator::FileSystem::MakeDirectory(GeneratorT genType, + std::string const& dirname) +{ + if (!MakeDirectory(dirname)) { + Log()->ErrorFile(genType, dirname, "Could not create directory"); + return false; + } + return true; +} + +bool cmQtAutoGenerator::FileSystem::MakeParentDirectory( + std::string const& filename) +{ + bool success = true; + std::string const dirName = cmSystemTools::GetFilenamePath(filename); + if (!dirName.empty()) { + success = MakeDirectory(dirName); + } + return success; +} + +bool cmQtAutoGenerator::FileSystem::MakeParentDirectory( + GeneratorT genType, std::string const& filename) +{ + if (!MakeParentDirectory(filename)) { + Log()->ErrorFile(genType, filename, "Could not create parent directory"); + return false; + } + return true; +} + +int cmQtAutoGenerator::ReadOnlyProcessT::PipeT::init(uv_loop_t* uv_loop, + ReadOnlyProcessT* process) +{ + Process_ = process; + Target_ = nullptr; + return UVPipe_.init(*uv_loop, 0, this); +} + +int cmQtAutoGenerator::ReadOnlyProcessT::PipeT::startRead(std::string* target) +{ + Target_ = target; + return uv_read_start(uv_stream(), &PipeT::UVAlloc, &PipeT::UVData); +} + +void cmQtAutoGenerator::ReadOnlyProcessT::PipeT::reset() +{ + Process_ = nullptr; + Target_ = nullptr; + UVPipe_.reset(); + Buffer_.clear(); + Buffer_.shrink_to_fit(); +} + +void cmQtAutoGenerator::ReadOnlyProcessT::PipeT::UVAlloc(uv_handle_t* handle, + size_t suggestedSize, + uv_buf_t* buf) +{ + auto& pipe = *reinterpret_cast<PipeT*>(handle->data); + pipe.Buffer_.resize(suggestedSize); + buf->base = &pipe.Buffer_.front(); + buf->len = pipe.Buffer_.size(); +} + +void cmQtAutoGenerator::ReadOnlyProcessT::PipeT::UVData(uv_stream_t* stream, + ssize_t nread, + const uv_buf_t* buf) +{ + auto& pipe = *reinterpret_cast<PipeT*>(stream->data); + if (nread > 0) { + // Append data to merged output + if ((buf->base != nullptr) && (pipe.Target_ != nullptr)) { + pipe.Target_->append(buf->base, nread); + } + } else if (nread < 0) { + // EOF or error + auto* proc = pipe.Process_; + // Check it this an unusual error + if (nread != UV_EOF) { + if (!proc->Result()->error()) { + proc->Result()->ErrorMessage = + "libuv reading from pipe failed with error code "; + proc->Result()->ErrorMessage += std::to_string(nread); + } + } + // Clear libuv pipe handle and try to finish + pipe.reset(); + proc->UVTryFinish(); + } +} + +void cmQtAutoGenerator::ProcessResultT::reset() +{ + ExitStatus = 0; + TermSignal = 0; + if (!StdOut.empty()) { + StdOut.clear(); + StdOut.shrink_to_fit(); + } + if (!StdErr.empty()) { + StdErr.clear(); + StdErr.shrink_to_fit(); + } + if (!ErrorMessage.empty()) { + ErrorMessage.clear(); + ErrorMessage.shrink_to_fit(); + } +} + +void cmQtAutoGenerator::ReadOnlyProcessT::setup( + ProcessResultT* result, bool mergedOutput, + std::vector<std::string> const& command, std::string const& workingDirectory) +{ + Setup_.WorkingDirectory = workingDirectory; + Setup_.Command = command; + Setup_.Result = result; + Setup_.MergedOutput = mergedOutput; +} + +bool cmQtAutoGenerator::ReadOnlyProcessT::start( + uv_loop_t* uv_loop, std::function<void()>&& finishedCallback) +{ + if (IsStarted() || (Result() == nullptr)) { + return false; + } + + // Reset result before the start + Result()->reset(); + + // Fill command string pointers + if (!Setup().Command.empty()) { + CommandPtr_.reserve(Setup().Command.size() + 1); + for (std::string const& arg : Setup().Command) { + CommandPtr_.push_back(arg.c_str()); + } + CommandPtr_.push_back(nullptr); + } else { + Result()->ErrorMessage = "Empty command"; + } + + if (!Result()->error()) { + if (UVPipeOut_.init(uv_loop, this) != 0) { + Result()->ErrorMessage = "libuv stdout pipe initialization failed"; + } + } + if (!Result()->error()) { + if (UVPipeErr_.init(uv_loop, this) != 0) { + Result()->ErrorMessage = "libuv stderr pipe initialization failed"; + } + } + if (!Result()->error()) { + // -- Setup process stdio options + // stdin + UVOptionsStdIO_[0].flags = UV_IGNORE; + UVOptionsStdIO_[0].data.stream = nullptr; + // stdout + UVOptionsStdIO_[1].flags = + static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE); + UVOptionsStdIO_[1].data.stream = UVPipeOut_.uv_stream(); + // stderr + UVOptionsStdIO_[2].flags = + static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE); + UVOptionsStdIO_[2].data.stream = UVPipeErr_.uv_stream(); + + // -- Setup process options + std::fill_n(reinterpret_cast<char*>(&UVOptions_), sizeof(UVOptions_), 0); + UVOptions_.exit_cb = &ReadOnlyProcessT::UVExit; + UVOptions_.file = CommandPtr_[0]; + UVOptions_.args = const_cast<char**>(&CommandPtr_.front()); + UVOptions_.cwd = Setup_.WorkingDirectory.c_str(); + UVOptions_.flags = UV_PROCESS_WINDOWS_HIDE; + UVOptions_.stdio_count = static_cast<int>(UVOptionsStdIO_.size()); + UVOptions_.stdio = &UVOptionsStdIO_.front(); + + // -- Spawn process + if (UVProcess_.spawn(*uv_loop, UVOptions_, this) != 0) { + Result()->ErrorMessage = "libuv process spawn failed"; + } + } + // -- Start reading from stdio streams + if (!Result()->error()) { + if (UVPipeOut_.startRead(&Result()->StdOut) != 0) { + Result()->ErrorMessage = "libuv start reading from stdout pipe failed"; + } + } + if (!Result()->error()) { + if (UVPipeErr_.startRead(Setup_.MergedOutput ? &Result()->StdOut + : &Result()->StdErr) != 0) { + Result()->ErrorMessage = "libuv start reading from stderr pipe failed"; + } + } + + if (!Result()->error()) { + IsStarted_ = true; + FinishedCallback_ = std::move(finishedCallback); + } else { + // Clear libuv handles and finish + UVProcess_.reset(); + UVPipeOut_.reset(); + UVPipeErr_.reset(); + CommandPtr_.clear(); + } + + return IsStarted(); +} + +void cmQtAutoGenerator::ReadOnlyProcessT::UVExit(uv_process_t* handle, + int64_t exitStatus, + int termSignal) +{ + auto& proc = *reinterpret_cast<ReadOnlyProcessT*>(handle->data); + if (proc.IsStarted() && !proc.IsFinished()) { + // Set error message on demand + proc.Result()->ExitStatus = exitStatus; + proc.Result()->TermSignal = termSignal; + if (!proc.Result()->error()) { + if (termSignal != 0) { + proc.Result()->ErrorMessage = "Process was terminated by signal "; + proc.Result()->ErrorMessage += + std::to_string(proc.Result()->TermSignal); + } else if (exitStatus != 0) { + proc.Result()->ErrorMessage = "Process failed with return value "; + proc.Result()->ErrorMessage += + std::to_string(proc.Result()->ExitStatus); + } + } + + // Reset process handle and try to finish + proc.UVProcess_.reset(); + proc.UVTryFinish(); + } +} + +void cmQtAutoGenerator::ReadOnlyProcessT::UVTryFinish() +{ + // There still might be data in the pipes after the process has finished. + // Therefore check if the process is finished AND all pipes are closed + // before signaling the worker thread to continue. + if (UVProcess_.get() == nullptr) { + if (UVPipeOut_.uv_pipe() == nullptr) { + if (UVPipeErr_.uv_pipe() == nullptr) { + IsFinished_ = true; + FinishedCallback_(); + } + } + } +} + +cmQtAutoGenerator::cmQtAutoGenerator() + : FileSys_(&Logger_) +{ + // Initialize logger + Logger_.SetVerbose(cmSystemTools::HasEnv("VERBOSE")); + { + std::string colorEnv; + cmSystemTools::GetEnv("COLOR", colorEnv); + if (!colorEnv.empty()) { + Logger_.SetColorOutput(cmSystemTools::IsOn(colorEnv.c_str())); + } else { + Logger_.SetColorOutput(true); + } + } + + // Initialize libuv loop + uv_disable_stdio_inheritance(); +#ifdef CMAKE_UV_SIGNAL_HACK + UVHackRAII_ = cm::make_unique<cmUVSignalHackRAII>(); +#endif + UVLoop_ = cm::make_unique<uv_loop_t>(); + uv_loop_init(UVLoop()); +} + +cmQtAutoGenerator::~cmQtAutoGenerator() +{ + // Close libuv loop + uv_loop_close(UVLoop()); +} + +bool cmQtAutoGenerator::Run(std::string const& infoFile, + std::string const& config) +{ + // Info settings + InfoFile_ = infoFile; + cmSystemTools::ConvertToUnixSlashes(InfoFile_); + InfoDir_ = cmSystemTools::GetFilenamePath(infoFile); + InfoConfig_ = config; + + bool success = false; + { + cmake cm(cmake::RoleScript); + cm.SetHomeOutputDirectory(InfoDir()); + cm.SetHomeDirectory(InfoDir()); + cm.GetCurrentSnapshot().SetDefaultDefinitions(); + cmGlobalGenerator gg(&cm); + + cmStateSnapshot snapshot = cm.GetCurrentSnapshot(); + snapshot.GetDirectory().SetCurrentBinary(InfoDir()); + snapshot.GetDirectory().SetCurrentSource(InfoDir()); + + auto makefile = cm::make_unique<cmMakefile>(&gg, snapshot); + // The OLD/WARN behavior for policy CMP0053 caused a speed regression. + // https://gitlab.kitware.com/cmake/cmake/issues/17570 + makefile->SetPolicyVersion("3.9"); + gg.SetCurrentMakefile(makefile.get()); + success = this->Init(makefile.get()); + } + if (success) { + success = this->Process(); + } + return success; +} + +std::string cmQtAutoGenerator::SettingsFind(std::string const& content, + const char* key) +{ + std::string prefix(key); + prefix += ':'; + std::string::size_type pos = content.find(prefix); + if (pos != std::string::npos) { + pos += prefix.size(); + if (pos < content.size()) { + std::string::size_type posE = content.find('\n', pos); + if ((posE != std::string::npos) && (posE != pos)) { + return content.substr(pos, posE - pos); + } + } + } + return std::string(); +} diff --git a/Source/cmQtAutoGenerator.h b/Source/cmQtAutoGenerator.h new file mode 100644 index 0000000..e029d8d --- /dev/null +++ b/Source/cmQtAutoGenerator.h @@ -0,0 +1,252 @@ +/* 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 "cmUVHandlePtr.h" +#include "cmUVSignalHackRAII.h" // IWYU pragma: keep +#include "cm_uv.h" + +#include <array> +#include <functional> +#include <mutex> +#include <stddef.h> +#include <stdint.h> +#include <string> +#include <vector> + +class cmMakefile; + +/// @brief Base class for QtAutoGen gernerators +class cmQtAutoGenerator : public cmQtAutoGen +{ + CM_DISABLE_COPY(cmQtAutoGenerator) +public: + // -- Types + + /// @brief Thread safe logging + class Logger + { + public: + // -- Verbosity + bool Verbose() const { return this->Verbose_; } + void SetVerbose(bool value); + bool ColorOutput() const { return this->ColorOutput_; } + void SetColorOutput(bool value); + // -- Log info + void Info(GeneratorT genType, std::string const& message); + // -- Log warning + void Warning(GeneratorT genType, std::string const& message); + void WarningFile(GeneratorT genType, std::string const& filename, + std::string const& message); + // -- Log error + void Error(GeneratorT genType, std::string const& message); + void ErrorFile(GeneratorT genType, std::string const& filename, + std::string const& message); + void ErrorCommand(GeneratorT genType, std::string const& message, + std::vector<std::string> const& command, + std::string const& output); + + private: + static std::string HeadLine(std::string const& title); + + private: + std::mutex Mutex_; + bool volatile Verbose_ = false; + bool volatile ColorOutput_ = false; + }; + + /// @brief Thread safe file system interface + class FileSystem + { + public: + FileSystem(Logger* log) + : Log_(log) + { + } + + Logger* Log() const { return Log_; } + std::string RealPath(std::string const& filename); + bool FileExists(std::string const& filename); + 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); + /// @brief Error logging version + bool FileRead(GeneratorT genType, std::string& content, + std::string const& filename); + + bool FileWrite(std::string const& filename, std::string const& content, + std::string* error = nullptr); + /// @brief Error logging version + bool FileWrite(GeneratorT genType, std::string const& filename, + std::string const& content); + + bool FileDiffers(std::string const& filename, std::string const& content); + + bool FileRemove(std::string const& filename); + bool Touch(std::string const& filename); + + bool MakeDirectory(std::string const& dirname); + /// @brief Error logging version + bool MakeDirectory(GeneratorT genType, std::string const& dirname); + + bool MakeParentDirectory(std::string const& filename); + /// @brief Error logging version + bool MakeParentDirectory(GeneratorT genType, std::string const& filename); + + private: + std::mutex Mutex_; + Logger* Log_; + }; + + /// @brief Return value and output of an external process + struct ProcessResultT + { + void reset(); + bool error() const + { + return (ExitStatus != 0) || (TermSignal != 0) || !ErrorMessage.empty(); + } + + std::int64_t ExitStatus = 0; + int TermSignal = 0; + std::string StdOut; + std::string StdErr; + std::string ErrorMessage; + }; + + /// @brief External process management class + struct ReadOnlyProcessT + { + // -- Types + + /// @brief libuv pipe buffer class + class PipeT + { + public: + int init(uv_loop_t* uv_loop, ReadOnlyProcessT* process); + int startRead(std::string* target); + void reset(); + + // -- Libuv casts + uv_pipe_t* uv_pipe() { return UVPipe_.get(); } + uv_stream_t* uv_stream() + { + return reinterpret_cast<uv_stream_t*>(uv_pipe()); + } + uv_handle_t* uv_handle() + { + return reinterpret_cast<uv_handle_t*>(uv_pipe()); + } + + // -- Libuv callbacks + static void UVAlloc(uv_handle_t* handle, size_t suggestedSize, + uv_buf_t* buf); + static void UVData(uv_stream_t* stream, ssize_t nread, + const uv_buf_t* buf); + + private: + ReadOnlyProcessT* Process_ = nullptr; + std::string* Target_ = nullptr; + std::vector<char> Buffer_; + cm::uv_pipe_ptr UVPipe_; + }; + + /// @brief Process settings + struct SetupT + { + std::string WorkingDirectory; + std::vector<std::string> Command; + ProcessResultT* Result = nullptr; + bool MergedOutput = false; + }; + + // -- Constructor + ReadOnlyProcessT() = default; + + // -- Const accessors + const SetupT& Setup() const { return Setup_; } + ProcessResultT* Result() const { return Setup_.Result; } + bool IsStarted() const { return IsStarted_; } + bool IsFinished() const { return IsFinished_; } + + // -- Runtime + void setup(ProcessResultT* result, bool mergedOutput, + std::vector<std::string> const& command, + std::string const& workingDirectory = std::string()); + bool start(uv_loop_t* uv_loop, std::function<void()>&& finishedCallback); + + private: + // -- Friends + friend class PipeT; + // -- Libuv callbacks + static void UVExit(uv_process_t* handle, int64_t exitStatus, + int termSignal); + void UVTryFinish(); + + // -- Setup + SetupT Setup_; + // -- Runtime + bool IsStarted_ = false; + bool IsFinished_ = false; + std::function<void()> FinishedCallback_; + std::vector<const char*> CommandPtr_; + std::array<uv_stdio_container_t, 3> UVOptionsStdIO_; + uv_process_options_t UVOptions_; + cm::uv_process_ptr UVProcess_; + PipeT UVPipeOut_; + PipeT UVPipeErr_; + }; + +public: + // -- Constructors + cmQtAutoGenerator(); + virtual ~cmQtAutoGenerator(); + + // -- Run + bool Run(std::string const& infoFile, std::string const& config); + + // -- Accessors + // Logging + Logger& Log() { return Logger_; } + // File System + FileSystem& FileSys() { return FileSys_; } + // InfoFile + std::string const& InfoFile() const { return InfoFile_; } + std::string const& InfoDir() const { return InfoDir_; } + std::string const& InfoConfig() const { return InfoConfig_; } + // libuv loop + uv_loop_t* UVLoop() { return UVLoop_.get(); } + cm::uv_async_ptr& UVRequest() { return UVRequest_; } + + // -- Utility + static std::string SettingsFind(std::string const& content, const char* key); + +protected: + // -- Abstract processing interface + virtual bool Init(cmMakefile* makefile) = 0; + virtual bool Process() = 0; + +private: + // -- Logging + Logger Logger_; + FileSystem FileSys_; + // -- Info settings + std::string InfoFile_; + std::string InfoDir_; + std::string InfoConfig_; +// -- libuv loop +#ifdef CMAKE_UV_SIGNAL_HACK + std::unique_ptr<cmUVSignalHackRAII> UVHackRAII_; +#endif + std::unique_ptr<uv_loop_t> UVLoop_; + cm::uv_async_ptr UVRequest_; +}; + +#endif diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx deleted file mode 100644 index 89568c3..0000000 --- a/Source/cmQtAutoGeneratorInitializer.cxx +++ /dev/null @@ -1,1236 +0,0 @@ -/* 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 "cmQtAutoGeneratorInitializer.h" - -#include "cmAlgorithms.h" -#include "cmCustomCommand.h" -#include "cmCustomCommandLines.h" -#include "cmFilePathChecksum.h" -#include "cmGeneratorTarget.h" -#include "cmGlobalGenerator.h" -#include "cmLinkItem.h" -#include "cmLocalGenerator.h" -#include "cmMakefile.h" -#include "cmOutputConverter.h" -#include "cmPolicies.h" -#include "cmSourceFile.h" -#include "cmSourceGroup.h" -#include "cmState.h" -#include "cmStateTypes.h" -#include "cmSystemTools.h" -#include "cmTarget.h" -#include "cm_sys_stat.h" -#include "cmake.h" -#include "cmsys/FStream.hxx" - -#include <algorithm> -#include <array> -#include <deque> -#include <map> -#include <set> -#include <sstream> -#include <string> -#include <utility> -#include <vector> - -inline static const char* SafeString(const char* value) -{ - return (value != nullptr) ? value : ""; -} - -inline static std::string GetSafeProperty(cmGeneratorTarget const* target, - const char* key) -{ - return std::string(SafeString(target->GetProperty(key))); -} - -inline static std::string GetSafeProperty(cmSourceFile const* sf, - const char* key) -{ - 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) -{ - makefile->AddDefinition(key, - cmOutputConverter::EscapeForCMake(value).c_str()); -} - -static void AddDefinitionEscaped(cmMakefile* makefile, const char* key, - const std::vector<std::string>& values) -{ - makefile->AddDefinition( - key, cmOutputConverter::EscapeForCMake(cmJoin(values, ";")).c_str()); -} - -static void AddDefinitionEscaped(cmMakefile* makefile, const char* key, - const std::set<std::string>& values) -{ - makefile->AddDefinition( - key, cmOutputConverter::EscapeForCMake(cmJoin(values, ";")).c_str()); -} - -static void AddDefinitionEscaped( - cmMakefile* makefile, const char* key, - const std::vector<std::vector<std::string>>& lists) -{ - std::vector<std::string> seplist; - for (const std::vector<std::string>& list : lists) { - std::string blist = "{"; - blist += cmJoin(list, ";"); - blist += "}"; - seplist.push_back(std::move(blist)); - } - makefile->AddDefinition(key, cmOutputConverter::EscapeForCMake( - cmJoin(seplist, cmQtAutoGen::listSep)) - .c_str()); -} - -static bool AddToSourceGroup(cmMakefile* makefile, std::string const& fileName, - cmQtAutoGen::Generator genType) -{ - cmSourceGroup* sourceGroup = nullptr; - // Acquire source group - { - std::string property; - std::string groupName; - { - std::array<std::string, 2> props; - // Use generator specific group name - switch (genType) { - case cmQtAutoGen::MOC: - props[0] = "AUTOMOC_SOURCE_GROUP"; - break; - case cmQtAutoGen::RCC: - props[0] = "AUTORCC_SOURCE_GROUP"; - break; - default: - props[0] = "AUTOGEN_SOURCE_GROUP"; - break; - } - props[1] = "AUTOGEN_SOURCE_GROUP"; - for (std::string& prop : props) { - const char* propName = makefile->GetState()->GetGlobalProperty(prop); - if ((propName != nullptr) && (*propName != '\0')) { - groupName = propName; - property = std::move(prop); - break; - } - } - } - // Generate a source group on demand - if (!groupName.empty()) { - sourceGroup = makefile->GetOrCreateSourceGroup(groupName); - if (sourceGroup == nullptr) { - std::ostringstream ost; - ost << cmQtAutoGen::GeneratorNameUpper(genType); - ost << ": " << property; - ost << ": Could not find or create the source group "; - ost << cmQtAutoGen::Quoted(groupName); - cmSystemTools::Error(ost.str().c_str()); - return false; - } - } - } - if (sourceGroup != nullptr) { - sourceGroup->AddGroupFile(fileName); - } - return true; -} - -static void AddCleanFile(cmMakefile* makefile, std::string const& fileName) -{ - makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", fileName.c_str(), - 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) -{ - 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)); - } - } - { - 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); - } - } - - return genFiles; -} - -/* @brief Tests if targetDepend is a STATIC_LIBRARY and if any of its - * recursive STATIC_LIBRARY dependencies depends on targetOrigin - * (STATIC_LIBRARY cycle). - */ -static bool StaticLibraryCycle(cmGeneratorTarget const* targetOrigin, - cmGeneratorTarget const* targetDepend, - std::string const& config) -{ - bool cycle = false; - if ((targetOrigin->GetType() == cmStateEnums::STATIC_LIBRARY) && - (targetDepend->GetType() == cmStateEnums::STATIC_LIBRARY)) { - std::set<cmGeneratorTarget const*> knownLibs; - std::deque<cmGeneratorTarget const*> testLibs; - - // Insert initial static_library dependency - knownLibs.insert(targetDepend); - testLibs.push_back(targetDepend); - - while (!testLibs.empty()) { - cmGeneratorTarget const* testTarget = testLibs.front(); - testLibs.pop_front(); - // Check if the test target is the origin target (cycle) - if (testTarget == targetOrigin) { - cycle = true; - break; - } - // Collect all static_library dependencies from the test target - cmLinkImplementationLibraries const* libs = - testTarget->GetLinkImplementationLibraries(config); - if (libs != nullptr) { - for (cmLinkItem const& item : libs->Libraries) { - cmGeneratorTarget const* depTarget = item.Target; - if ((depTarget != nullptr) && - (depTarget->GetType() == cmStateEnums::STATIC_LIBRARY) && - knownLibs.insert(depTarget).second) { - testLibs.push_back(depTarget); - } - } - } - } - } - 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) -{ - // Read skip files from makefile sources - { - std::string pathError; - for (cmSourceFile* sf : digest.Target->Makefile->GetSourceFiles()) { - // sf->GetExtension() is only valid after sf->GetFullPath() ... - // Since we're iterating over source files that might be not in the - // target we need to check for path errors (not existing files). - std::string const& fPath = sf->GetFullPath(&pathError); - if (!pathError.empty()) { - pathError.clear(); - continue; - } - 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); - } - } - } - } -} - -static void SetupAutoTargetMoc(cmQtAutoGenDigest const& digest, - std::string const& configDefault, - std::vector<std::string> const& configsList, - cmQtAutoGenSetup& setup) -{ - 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, ";"); - }; - - // 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); - } - - // Moc executable - { - 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 (err.empty()) { - AddDefinitionEscaped(makefile, "_qt_moc_executable", mocExec); - } else { - err += " (" + target->GetName() + ")"; - cmSystemTools::Error(err.c_str()); - } - } -} - -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(); - - // Uic search paths - { - 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); - } - } - } - 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, ";"); - }; - - // 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"; - std::string pathError; - for (cmSourceFile* sf : makefile->GetSourceFiles()) { - // sf->GetExtension() is only valid after sf->GetFullPath() ... - // Since we're iterating over source files that might be not in the - // target we need to check for path errors (not existing files). - std::string const& fPath = sf->GetFullPath(&pathError); - if (!pathError.empty()) { - pathError.clear(); - continue; - } - 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); - } - - AddDefinitionEscaped(makefile, "_uic_skip", setup.UicSkip); - - // Uic executable - { - std::string err; - std::string uicExec; - - 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()); - } - } -} - -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"; - } - } 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"; - } - } 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); - // Remove old settings on cleanup - { - std::string base = autogenInfoDir + "/AutogenOldSettings"; - if (multiConfig == cmQtAutoGen::SINGLE) { - AddCleanFile(makefile, base.append(".cmake")); - } else { - for (std::string const& cfg : configsList) { - std::string filename = base; - filename += "_"; - filename += cfg; - filename += ".cmake"; - AddCleanFile(makefile, filename); - } - } - } - - // 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); - 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) { - includeDir += "_$<CONFIG>"; - } - target->AddIncludeDirectory(includeDir, true); - } - - // Extract relevant source files - std::vector<std::string> generatedSources; - std::vector<std::string> generatedHeaders; - { - std::string const qrcExt = "qrc"; - std::vector<cmSourceFile*> srcFiles; - target->GetConfigCommonSourceFiles(srcFiles); - for (cmSourceFile* sf : srcFiles) { - if (sf->GetPropertyAsBool("SKIP_AUTOGEN")) { - continue; - } - // sf->GetExtension() is only valid after sf->GetFullPath() ... - 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) { - 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"))) { - // 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); - } - } else { - if (generated) { - generatedSources.push_back(absPath); - } else { - digest.Sources.push_back(absPath); - } - } - } - } - } - // Register rcc enabled files - if (digest.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"); - // RCC options - { - std::string const opts = GetSafeProperty(sf, "AUTORCC_OPTIONS"); - if (!opts.empty()) { - cmSystemTools::ExpandListArgument(opts, qrcDigest.Options); - } - } - digest.Qrcs.push_back(std::move(qrcDigest)); - } - } - } - // cmGeneratorTarget::GetConfigCommonSourceFiles computes the target's - // 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(); - } - - // Process GENERATED sources and headers - if (!generatedSources.empty() || !generatedHeaders.empty()) { - // Check status of policy CMP0071 - bool policyAccept = false; - bool policyWarn = false; - cmPolicies::PolicyStatus const CMP0071_status = - target->Makefile->GetPolicyStatus(cmPolicies::CMP0071); - switch (CMP0071_status) { - case cmPolicies::WARN: - policyWarn = true; - CM_FALLTHROUGH; - case cmPolicies::OLD: - // Ignore GENERATED file - break; - case cmPolicies::REQUIRED_IF_USED: - case cmPolicies::REQUIRED_ALWAYS: - case cmPolicies::NEW: - // Process GENERATED file - policyAccept = true; - break; - } - - if (policyAccept) { - // Accept GENERATED sources - for (std::string const& absFile : generatedHeaders) { - digest.Headers.push_back(absFile); - autogenDependFiles.insert(absFile); - } - for (std::string const& absFile : generatedSources) { - digest.Sources.push_back(absFile); - autogenDependFiles.insert(absFile); - } - } else { - if (policyWarn) { - std::string msg; - msg += cmPolicies::GetPolicyWarning(cmPolicies::CMP0071); - msg += "\n"; - std::string tools; - std::string property; - if (digest.MocEnabled && digest.UicEnabled) { - tools = "AUTOMOC and AUTOUIC"; - property = "SKIP_AUTOGEN"; - } else if (digest.MocEnabled) { - tools = "AUTOMOC"; - property = "SKIP_AUTOMOC"; - } else if (digest.UicEnabled) { - tools = "AUTOUIC"; - property = "SKIP_AUTOUIC"; - } - msg += "For compatibility, CMake is excluding the GENERATED source " - "file(s):\n"; - for (const std::string& absFile : generatedHeaders) { - msg.append(" ").append(cmQtAutoGen::Quoted(absFile)).append("\n"); - } - for (const std::string& absFile : generatedSources) { - msg.append(" ").append(cmQtAutoGen::Quoted(absFile)).append("\n"); - } - msg += "from processing by "; - msg += tools; - msg += - ". If any of the files should be processed, set CMP0071 to NEW. " - "If any of the files should not be processed, " - "explicitly exclude them by setting the source file property "; - msg += property; - msg += ":\n set_property(SOURCE file.h PROPERTY "; - msg += property; - msg += " ON)\n"; - makefile->IssueMessage(cmake::AUTHOR_WARNING, msg); - } - } - } - // Sort headers and sources - std::sort(digest.Headers.begin(), digest.Headers.end()); - std::sort(digest.Sources.begin(), digest.Sources.end()); - - // Process qrc files - if (!digest.Qrcs.empty()) { - const bool QtV5 = (digest.QtVersionMajor == "5"); - std::string const rcc = RccGetExecutable(target, digest.QtVersionMajor); - // Target rcc options - std::vector<std::string> optionsTarget; - cmSystemTools::ExpandListArgument( - GetSafeProperty(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; - break; - } - } - } - // Path checksum - { - cmFilePathChecksum const fpathCheckSum(makefile); - for (cmQtAutoGenDigestQrc& qrcDigest : digest.Qrcs) { - qrcDigest.PathChecksum = fpathCheckSum.getPart(qrcDigest.QrcFile); - // RCC output file name - std::string rccFile = autogenBuildDir + "/"; - rccFile += qrcDigest.PathChecksum; - rccFile += "/qrc_"; - rccFile += qrcDigest.QrcName; - rccFile += ".cpp"; - qrcDigest.RccFile = std::move(rccFile); - } - } - // RCC options - for (cmQtAutoGenDigestQrc& qrcDigest : digest.Qrcs) { - // Target options - std::vector<std::string> opts = optionsTarget; - // Merge computed "-name XYZ" option - { - std::string name = qrcDigest.QrcName; - // Replace '-' with '_'. The former is not valid for symbol names. - std::replace(name.begin(), name.end(), '-', '_'); - if (!qrcDigest.Unique) { - name += "_"; - name += qrcDigest.PathChecksum; - } - std::vector<std::string> nameOpts; - nameOpts.emplace_back("-name"); - nameOpts.emplace_back(std::move(name)); - cmQtAutoGen::RccMergeOptions(opts, nameOpts, QtV5); - } - // Merge file option - cmQtAutoGen::RccMergeOptions(opts, qrcDigest.Options, QtV5); - qrcDigest.Options = std::move(opts); - } - for (cmQtAutoGenDigestQrc& qrcDigest : digest.Qrcs) { - // Register file at target - { - auto files = AddGeneratedSource(target, qrcDigest.RccFile, multiConfig, - configsList, cmQtAutoGen::RCC); - for (std::string& file : files) { - autogenProvides.push_back(std::move(file)); - } - } - // Dependencies - if (qrcDigest.Generated) { - // Add the GENERATED .qrc file to the dependencies - autogenDependFiles.insert(qrcDigest.QrcFile); - } else { - // Add the resource files to the dependencies - { - std::string error; - if (cmQtAutoGen::RccListInputs(digest.QtVersionMajor, rcc, - qrcDigest.QrcFile, - qrcDigest.Resources, &error)) { - for (std::string const& fileName : qrcDigest.Resources) { - autogenDependFiles.insert(fileName); - } - } else { - cmSystemTools::Error(error.c_str()); - } - } - // Run cmake again when .qrc file changes - makefile->AddCMakeDependFile(qrcDigest.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); - } - } - } - } - - // 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) { - target->Target->AddUtility(depTarget->GetName(), makefile); - } - - // 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 { - - // Add link library target dependencies to the autogen target dependencies - { - // add_dependencies/addUtility do not support generator expressions. - // We depend only on the libraries found in all configs therefore. - std::map<cmGeneratorTarget const*, std::size_t> commonTargets; - 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)) { - // Increment target config count - commonTargets[libTarget]++; - } - } - } - } - for (auto const& item : commonTargets) { - if (item.second == configsList.size()) { - autogenDependTargets.insert(item.first->Target); - } - } - } - - // Create autogen target - cmTarget* autogenTarget = makefile->AddUtilityCommand( - autogenTargetName, true, workingDirectory.c_str(), - /*byproducts=*/autogenProvides, - std::vector<std::string>(autogenDependFiles.begin(), - autogenDependFiles.end()), - 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"); - } - // Inherit FOLDER property from target (#13688) - if (autogenFolder == nullptr) { - autogenFolder = SafeString(target->Target->GetProperty("FOLDER")); - } - if ((autogenFolder != nullptr) && (*autogenFolder != '\0')) { - autogenTarget->SetProperty("FOLDER", autogenFolder); - } - } - - // Add autogen target to the origin target dependencies - target->Target->AddUtility(autogenTargetName, makefile); - } -} - -void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget( - cmQtAutoGenDigest const& digest) -{ - cmGeneratorTarget const* target = digest.Target; - cmMakefile* makefile = target->Target->GetMakefile(); - cmQtAutoGen::MultiConfig const multiConfig = - AutogenMultiConfig(target->GetGlobalGenerator()); - - // forget the variables added here afterwards again: - cmMakefile::ScopePushPop varScope(makefile); - static_cast<void>(varScope); - - // Configurations - std::string configDefault; - std::vector<std::string> configsList; - std::map<std::string, std::string> configSuffixes; - { - configDefault = makefile->GetConfigurations(configsList); - if (configsList.empty()) { - configsList.push_back(""); - } - } - 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); - } - } - if (digest.RccEnabled) { - SetupAutoTargetRcc(digest); - } - } - - // 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 - // -------------------------------------- - - // Ensure we have write permission in case .in was read-only. - 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); - if (!(perm & mode_write)) { - cmSystemTools::SetPermissions(infoFile, perm | mode_write); - } - - // Open and write file - cmsys::ofstream ofs(infoFile.c_str(), std::ios::app); - if (ofs) { - 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"; - } - }; - 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); - } 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()); - } - } -} diff --git a/Source/cmQtAutoGeneratorInitializer.h b/Source/cmQtAutoGeneratorInitializer.h deleted file mode 100644 index b8a5ae4..0000000 --- a/Source/cmQtAutoGeneratorInitializer.h +++ /dev/null @@ -1,24 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#ifndef cmQtAutoGeneratorInitializer_h -#define cmQtAutoGeneratorInitializer_h - -#include "cmConfigure.h" // IWYU pragma: keep -#include "cmQtAutoGenDigest.h" - -#include <string> - -class cmGeneratorTarget; - -class cmQtAutoGeneratorInitializer -{ -public: - static std::string GetQtMajorVersion(cmGeneratorTarget const* target); - static std::string GetQtMinorVersion(cmGeneratorTarget const* target, - std::string const& qtVersionMajor); - - static void InitializeAutogenTarget(cmQtAutoGenDigest& digest); - static void SetupAutoGenerateTarget(cmQtAutoGenDigest const& digest); -}; - -#endif diff --git a/Source/cmQtAutoGeneratorMocUic.cxx b/Source/cmQtAutoGeneratorMocUic.cxx new file mode 100644 index 0000000..6be65ee --- /dev/null +++ b/Source/cmQtAutoGeneratorMocUic.cxx @@ -0,0 +1,2028 @@ +/* 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 "cmQtAutoGeneratorMocUic.h" + +#include <algorithm> +#include <array> +#include <functional> +#include <list> +#include <memory> +#include <sstream> +#include <utility> + +#include "cmAlgorithms.h" +#include "cmCryptoHash.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" +#include "cmake.h" + +#if defined(__APPLE__) +#include <unistd.h> +#endif + +// -- Class methods + +std::string cmQtAutoGeneratorMocUic::BaseSettingsT::AbsoluteBuildPath( + std::string const& relativePath) const +{ + return cmSystemTools::CollapseCombinedPath(AutogenBuildDir, relativePath); +} + +/** + * @brief Tries to find the header file to the given file base path by + * appending different header extensions + * @return True on success + */ +bool cmQtAutoGeneratorMocUic::BaseSettingsT::FindHeader( + std::string& header, std::string const& testBasePath) const +{ + for (std::string const& ext : HeaderExtensions) { + std::string testFilePath(testBasePath); + testFilePath.push_back('.'); + testFilePath += ext; + if (FileSys->FileExists(testFilePath)) { + header = testFilePath; + return true; + } + } + return false; +} + +bool cmQtAutoGeneratorMocUic::MocSettingsT::skipped( + std::string const& fileName) const +{ + return (!Enabled || (SkipList.find(fileName) != SkipList.end())); +} + +/** + * @brief Returns the first relevant Qt macro name found in the given C++ code + * @return The name of the Qt macro or an empty string + */ +std::string cmQtAutoGeneratorMocUic::MocSettingsT::FindMacro( + std::string const& content) const +{ + for (KeyExpT const& filter : MacroFilters) { + // Run a simple find string operation before the expensive + // regular expression check + if (content.find(filter.Key) != std::string::npos) { + cmsys::RegularExpressionMatch match; + if (filter.Exp.find(content.c_str(), match)) { + // Return macro name on demand + return filter.Key; + } + } + } + return std::string(); +} + +std::string cmQtAutoGeneratorMocUic::MocSettingsT::MacrosString() const +{ + std::string res; + const auto itB = MacroFilters.cbegin(); + const auto itE = MacroFilters.cend(); + const auto itL = itE - 1; + auto itC = itB; + for (; itC != itE; ++itC) { + // Separator + if (itC != itB) { + if (itC != itL) { + res += ", "; + } else { + res += " or "; + } + } + // Key + res += itC->Key; + } + return res; +} + +std::string cmQtAutoGeneratorMocUic::MocSettingsT::FindIncludedFile( + std::string const& sourcePath, std::string const& includeString) const +{ + // Search in vicinity of the source + { + std::string testPath = sourcePath; + testPath += includeString; + if (FileSys->FileExists(testPath)) { + return FileSys->RealPath(testPath); + } + } + // Search in include directories + for (std::string const& path : IncludePaths) { + std::string fullPath = path; + fullPath.push_back('/'); + fullPath += includeString; + if (FileSys->FileExists(fullPath)) { + return FileSys->RealPath(fullPath); + } + } + // Return empty string + return std::string(); +} + +void cmQtAutoGeneratorMocUic::MocSettingsT::FindDependencies( + std::string const& content, std::set<std::string>& depends) const +{ + if (!DependFilters.empty() && !content.empty()) { + for (KeyExpT const& filter : DependFilters) { + // Run a simple find string check + if (content.find(filter.Key) != std::string::npos) { + // Run the expensive regular expression check loop + const char* contentChars = content.c_str(); + cmsys::RegularExpressionMatch match; + while (filter.Exp.find(contentChars, match)) { + { + std::string dep = match.match(1); + if (!dep.empty()) { + depends.emplace(std::move(dep)); + } + } + contentChars += match.end(); + } + } + } + } +} + +bool cmQtAutoGeneratorMocUic::UicSettingsT::skipped( + std::string const& fileName) const +{ + return (!Enabled || (SkipList.find(fileName) != SkipList.end())); +} + +void cmQtAutoGeneratorMocUic::JobParseT::Process(WorkerT& wrk) +{ + if (AutoMoc && Header) { + // Don't parse header for moc if the file is included by a source already + if (wrk.Gen().ParallelMocIncluded(FileName)) { + AutoMoc = false; + } + } + + if (AutoMoc || AutoUic) { + std::string error; + MetaT meta; + if (wrk.FileSys().FileRead(meta.Content, FileName, &error)) { + if (!meta.Content.empty()) { + meta.FileDir = SubDirPrefix(FileName); + meta.FileBase = + cmSystemTools::GetFilenameWithoutLastExtension(FileName); + + bool success = true; + if (AutoMoc) { + if (Header) { + success = ParseMocHeader(wrk, meta); + } else { + success = ParseMocSource(wrk, meta); + } + } + if (AutoUic && success) { + ParseUic(wrk, meta); + } + } else { + wrk.LogFileWarning(GeneratorT::GEN, FileName, + "The source file is empty"); + } + } else { + wrk.LogFileError(GeneratorT::GEN, FileName, + "Could not read the file: " + error); + } + } +} + +bool cmQtAutoGeneratorMocUic::JobParseT::ParseMocSource(WorkerT& wrk, + MetaT const& meta) +{ + struct JobPre + { + bool self; // source file is self + bool underscore; // "moc_" style include + std::string SourceFile; + std::string IncludeString; + }; + + struct MocInclude + { + std::string Inc; // full include string + std::string Dir; // include string directory + std::string Base; // include string file base + }; + + // Check if this source file contains a relevant macro + std::string const ownMacro = wrk.Moc().FindMacro(meta.Content); + + // Extract moc includes from file + std::deque<MocInclude> mocIncsUsc; + std::deque<MocInclude> mocIncsDot; + { + if (meta.Content.find("moc") != std::string::npos) { + const char* contentChars = meta.Content.c_str(); + cmsys::RegularExpressionMatch match; + while (wrk.Moc().RegExpInclude.find(contentChars, match)) { + std::string incString = match.match(2); + std::string incDir(SubDirPrefix(incString)); + std::string incBase = + cmSystemTools::GetFilenameWithoutLastExtension(incString); + if (cmHasLiteralPrefix(incBase, "moc_")) { + // moc_<BASE>.cxx + // Remove the moc_ part from the base name + mocIncsUsc.emplace_back(MocInclude{ + std::move(incString), std::move(incDir), incBase.substr(4) }); + } else { + // <BASE>.moc + mocIncsDot.emplace_back(MocInclude{ + std::move(incString), std::move(incDir), std::move(incBase) }); + } + // Forward content pointer + contentChars += match.end(); + } + } + } + + // Check if there is anything to do + if (ownMacro.empty() && mocIncsUsc.empty() && mocIncsDot.empty()) { + return true; + } + + bool ownDotMocIncluded = false; + bool ownMocUscIncluded = false; + std::deque<JobPre> jobs; + + // Process moc_<BASE>.cxx includes + for (const MocInclude& mocInc : mocIncsUsc) { + std::string const header = + MocFindIncludedHeader(wrk, meta.FileDir, mocInc.Dir + mocInc.Base); + if (!header.empty()) { + // Check if header is skipped + if (wrk.Moc().skipped(header)) { + continue; + } + // Register moc job + const bool ownMoc = (mocInc.Base == meta.FileBase); + jobs.emplace_back(JobPre{ ownMoc, true, header, mocInc.Inc }); + // Store meta information for relaxed mode + if (ownMoc) { + ownMocUscIncluded = true; + } + } else { + { + std::string emsg = "The file includes the moc file "; + emsg += Quoted(mocInc.Inc); + emsg += ", but the header "; + emsg += Quoted(MocStringHeaders(wrk, mocInc.Base)); + emsg += " could not be found."; + wrk.LogFileError(GeneratorT::MOC, FileName, emsg); + } + return false; + } + } + + // Process <BASE>.moc includes + for (const MocInclude& mocInc : mocIncsDot) { + const bool ownMoc = (mocInc.Base == meta.FileBase); + if (wrk.Moc().RelaxedMode) { + // Relaxed mode + if (!ownMacro.empty() && ownMoc) { + // Add self + jobs.emplace_back(JobPre{ ownMoc, false, FileName, mocInc.Inc }); + ownDotMocIncluded = true; + } else { + // In relaxed mode try to find a header instead but issue a warning. + // This is for KDE4 compatibility + std::string const header = + MocFindIncludedHeader(wrk, meta.FileDir, mocInc.Dir + mocInc.Base); + if (!header.empty()) { + // Check if header is skipped + if (wrk.Moc().skipped(header)) { + continue; + } + // Register moc job + jobs.emplace_back(JobPre{ ownMoc, false, header, mocInc.Inc }); + if (ownMacro.empty()) { + if (ownMoc) { + std::string emsg = "The file includes the moc file "; + emsg += Quoted(mocInc.Inc); + emsg += ", but does not contain a "; + emsg += wrk.Moc().MacrosString(); + emsg += " macro.\nRunning moc on\n "; + emsg += Quoted(header); + emsg += "!\nBetter include "; + emsg += Quoted("moc_" + mocInc.Base + ".cpp"); + emsg += " for a compatibility with strict mode.\n" + "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n"; + wrk.LogFileWarning(GeneratorT::MOC, FileName, emsg); + } else { + std::string emsg = "The file includes the moc file "; + emsg += Quoted(mocInc.Inc); + emsg += " instead of "; + emsg += Quoted("moc_" + mocInc.Base + ".cpp"); + emsg += ".\nRunning moc on\n "; + emsg += Quoted(header); + emsg += "!\nBetter include "; + emsg += Quoted("moc_" + mocInc.Base + ".cpp"); + emsg += " for compatibility with strict mode.\n" + "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n"; + wrk.LogFileWarning(GeneratorT::MOC, FileName, emsg); + } + } + } else { + { + std::string emsg = "The file includes the moc file "; + emsg += Quoted(mocInc.Inc); + emsg += ", which seems to be the moc file from a different " + "source file.\nCMAKE_AUTOMOC_RELAXED_MODE: Also a " + "matching header "; + emsg += Quoted(MocStringHeaders(wrk, mocInc.Base)); + emsg += " could not be found."; + wrk.LogFileError(GeneratorT::MOC, FileName, emsg); + } + return false; + } + } + } else { + // Strict mode + if (ownMoc) { + // Include self + jobs.emplace_back(JobPre{ ownMoc, false, FileName, mocInc.Inc }); + ownDotMocIncluded = true; + // Accept but issue a warning if moc isn't required + if (ownMacro.empty()) { + std::string emsg = "The file includes the moc file "; + emsg += Quoted(mocInc.Inc); + emsg += ", but does not contain a "; + emsg += wrk.Moc().MacrosString(); + emsg += " macro."; + wrk.LogFileWarning(GeneratorT::MOC, FileName, emsg); + } + } else { + // Don't allow <BASE>.moc include other than self in strict mode + { + std::string emsg = "The file includes the moc file "; + emsg += Quoted(mocInc.Inc); + emsg += ", which seems to be the moc file from a different " + "source file.\nThis is not supported. Include "; + emsg += Quoted(meta.FileBase + ".moc"); + emsg += " to run moc on this source file."; + wrk.LogFileError(GeneratorT::MOC, FileName, emsg); + } + return false; + } + } + } + + if (!ownMacro.empty() && !ownDotMocIncluded) { + // In this case, check whether the scanned file itself contains a + // Q_OBJECT. + // If this is the case, the moc_foo.cpp should probably be generated from + // foo.cpp instead of foo.h, because otherwise it won't build. + // But warn, since this is not how it is supposed to be used. + // This is for KDE4 compatibility. + if (wrk.Moc().RelaxedMode && ownMocUscIncluded) { + JobPre uscJobPre; + // Remove underscore job request + { + auto itC = jobs.begin(); + auto itE = jobs.end(); + for (; itC != itE; ++itC) { + JobPre& job(*itC); + if (job.self && job.underscore) { + uscJobPre = std::move(job); + jobs.erase(itC); + break; + } + } + } + // Issue a warning + { + std::string emsg = "The file contains a "; + emsg += ownMacro; + emsg += " macro, but does not include "; + emsg += Quoted(meta.FileBase + ".moc"); + emsg += ". Instead it includes "; + emsg += Quoted(uscJobPre.IncludeString); + emsg += ".\nRunning moc on\n "; + emsg += Quoted(FileName); + emsg += "!\nBetter include "; + emsg += Quoted(meta.FileBase + ".moc"); + emsg += " for compatibility with strict mode.\n" + "(CMAKE_AUTOMOC_RELAXED_MODE warning)"; + wrk.LogFileWarning(GeneratorT::MOC, FileName, emsg); + } + // Add own source job + jobs.emplace_back( + JobPre{ true, false, FileName, uscJobPre.IncludeString }); + } else { + // Otherwise always error out since it will not compile. + { + std::string emsg = "The file contains a "; + emsg += ownMacro; + emsg += " macro, but does not include "; + emsg += Quoted(meta.FileBase + ".moc"); + emsg += "!\nConsider to\n - add #include \""; + emsg += meta.FileBase; + emsg += ".moc\"\n - enable SKIP_AUTOMOC for this file"; + wrk.LogFileError(GeneratorT::MOC, FileName, emsg); + } + return false; + } + } + + // Convert pre jobs to actual jobs + for (JobPre& jobPre : jobs) { + JobHandleT jobHandle(new JobMocT(std::move(jobPre.SourceFile), FileName, + std::move(jobPre.IncludeString))); + if (jobPre.self) { + // Read depdendencies from this source + static_cast<JobMocT&>(*jobHandle).FindDependencies(wrk, meta.Content); + } + if (!wrk.Gen().ParallelJobPushMoc(jobHandle)) { + return false; + } + } + return true; +} + +bool cmQtAutoGeneratorMocUic::JobParseT::ParseMocHeader(WorkerT& wrk, + MetaT const& meta) +{ + bool success = true; + std::string const macroName = wrk.Moc().FindMacro(meta.Content); + if (!macroName.empty()) { + JobHandleT jobHandle( + new JobMocT(std::string(FileName), std::string(), std::string())); + // Read depdendencies from this source + static_cast<JobMocT&>(*jobHandle).FindDependencies(wrk, meta.Content); + success = wrk.Gen().ParallelJobPushMoc(jobHandle); + } + return success; +} + +std::string cmQtAutoGeneratorMocUic::JobParseT::MocStringHeaders( + WorkerT& wrk, std::string const& fileBase) const +{ + std::string res = fileBase; + res += ".{"; + res += cmJoin(wrk.Base().HeaderExtensions, ","); + res += "}"; + return res; +} + +std::string cmQtAutoGeneratorMocUic::JobParseT::MocFindIncludedHeader( + WorkerT& wrk, std::string const& includerDir, std::string const& includeBase) +{ + std::string header; + // Search in vicinity of the source + if (!wrk.Base().FindHeader(header, includerDir + includeBase)) { + // Search in include directories + for (std::string const& path : wrk.Moc().IncludePaths) { + std::string fullPath = path; + fullPath.push_back('/'); + fullPath += includeBase; + if (wrk.Base().FindHeader(header, fullPath)) { + break; + } + } + } + // Sanitize + if (!header.empty()) { + header = wrk.FileSys().RealPath(header); + } + return header; +} + +bool cmQtAutoGeneratorMocUic::JobParseT::ParseUic(WorkerT& wrk, + MetaT const& meta) +{ + bool success = true; + if (meta.Content.find("ui_") != std::string::npos) { + const char* contentChars = meta.Content.c_str(); + cmsys::RegularExpressionMatch match; + while (wrk.Uic().RegExpInclude.find(contentChars, match)) { + if (!ParseUicInclude(wrk, meta, match.match(2))) { + success = false; + break; + } + contentChars += match.end(); + } + } + return success; +} + +bool cmQtAutoGeneratorMocUic::JobParseT::ParseUicInclude( + WorkerT& wrk, MetaT const& meta, std::string&& includeString) +{ + bool success = false; + std::string uiInputFile = UicFindIncludedFile(wrk, meta, includeString); + if (!uiInputFile.empty()) { + if (!wrk.Uic().skipped(uiInputFile)) { + JobHandleT jobHandle(new JobUicT(std::move(uiInputFile), FileName, + std::move(includeString))); + success = wrk.Gen().ParallelJobPushUic(jobHandle); + } else { + // A skipped file is successful + success = true; + } + } + return success; +} + +std::string cmQtAutoGeneratorMocUic::JobParseT::UicFindIncludedFile( + WorkerT& wrk, MetaT const& meta, std::string const& includeString) +{ + std::string res; + std::string searchFile = + cmSystemTools::GetFilenameWithoutLastExtension(includeString).substr(3); + searchFile += ".ui"; + // Collect search paths list + std::deque<std::string> testFiles; + { + std::string const searchPath = SubDirPrefix(includeString); + + std::string searchFileFull; + if (!searchPath.empty()) { + searchFileFull = searchPath; + searchFileFull += searchFile; + } + // Vicinity of the source + { + std::string const sourcePath = meta.FileDir; + testFiles.push_back(sourcePath + searchFile); + if (!searchPath.empty()) { + testFiles.push_back(sourcePath + searchFileFull); + } + } + // AUTOUIC search paths + if (!wrk.Uic().SearchPaths.empty()) { + for (std::string const& sPath : wrk.Uic().SearchPaths) { + testFiles.push_back((sPath + "/").append(searchFile)); + } + if (!searchPath.empty()) { + for (std::string const& sPath : wrk.Uic().SearchPaths) { + testFiles.push_back((sPath + "/").append(searchFileFull)); + } + } + } + } + + // Search for the .ui file! + for (std::string const& testFile : testFiles) { + if (wrk.FileSys().FileExists(testFile)) { + res = wrk.FileSys().RealPath(testFile); + break; + } + } + + // Log error + if (res.empty()) { + std::string emsg = "Could not find "; + emsg += Quoted(searchFile); + emsg += " in\n"; + for (std::string const& testFile : testFiles) { + emsg += " "; + emsg += Quoted(testFile); + emsg += "\n"; + } + wrk.LogFileError(GeneratorT::UIC, FileName, emsg); + } + + return res; +} + +void cmQtAutoGeneratorMocUic::JobMocPredefsT::Process(WorkerT& wrk) +{ + // (Re)generate moc_predefs.h on demand + bool generate(false); + bool fileExists(wrk.FileSys().FileExists(wrk.Moc().PredefsFileAbs)); + if (!fileExists) { + if (wrk.Log().Verbose()) { + std::string reason = "Generating "; + reason += Quoted(wrk.Moc().PredefsFileRel); + reason += " because it doesn't exist"; + wrk.LogInfo(GeneratorT::MOC, reason); + } + generate = true; + } else if (wrk.Moc().SettingsChanged) { + if (wrk.Log().Verbose()) { + std::string reason = "Generating "; + reason += Quoted(wrk.Moc().PredefsFileRel); + reason += " because the settings changed."; + wrk.LogInfo(GeneratorT::MOC, reason); + } + generate = true; + } + if (generate) { + ProcessResultT result; + { + // Compose command + std::vector<std::string> cmd = wrk.Moc().PredefsCmd; + // Add includes + cmd.insert(cmd.end(), wrk.Moc().Includes.begin(), + wrk.Moc().Includes.end()); + // Add definitions + for (std::string const& def : wrk.Moc().Definitions) { + cmd.push_back("-D" + def); + } + // Execute command + if (!wrk.RunProcess(GeneratorT::MOC, result, cmd)) { + std::string emsg = "The content generation command for "; + emsg += Quoted(wrk.Moc().PredefsFileRel); + emsg += " failed.\n"; + emsg += result.ErrorMessage; + wrk.LogCommandError(GeneratorT::MOC, emsg, cmd, result.StdOut); + } + } + + // (Re)write predefs file only on demand + if (!result.error()) { + if (!fileExists || + wrk.FileSys().FileDiffers(wrk.Moc().PredefsFileAbs, result.StdOut)) { + if (wrk.FileSys().FileWrite(GeneratorT::MOC, wrk.Moc().PredefsFileAbs, + result.StdOut)) { + // Success + } else { + std::string emsg = "Writing "; + emsg += Quoted(wrk.Moc().PredefsFileRel); + emsg += " failed."; + wrk.LogFileError(GeneratorT::MOC, wrk.Moc().PredefsFileAbs, emsg); + } + } else { + // Touch to update the time stamp + if (wrk.Log().Verbose()) { + std::string msg = "Touching "; + msg += Quoted(wrk.Moc().PredefsFileRel); + msg += "."; + wrk.LogInfo(GeneratorT::MOC, msg); + } + wrk.FileSys().Touch(wrk.Moc().PredefsFileAbs); + } + } + } +} + +void cmQtAutoGeneratorMocUic::JobMocT::FindDependencies( + WorkerT& wrk, std::string const& content) +{ + wrk.Moc().FindDependencies(content, Depends); + DependsValid = true; +} + +void cmQtAutoGeneratorMocUic::JobMocT::Process(WorkerT& wrk) +{ + // Compute build file name + if (!IncludeString.empty()) { + BuildFile = wrk.Base().AutogenIncludeDir; + BuildFile += '/'; + BuildFile += IncludeString; + } else { + std::string rel = wrk.Base().FilePathChecksum.getPart(SourceFile); + rel += "/moc_"; + rel += cmSystemTools::GetFilenameWithoutLastExtension(SourceFile); + rel += ".cpp"; + // Register relative file path + wrk.Gen().ParallelMocAutoRegister(rel); + // Absolute build path + if (wrk.Base().MultiConfig) { + BuildFile = wrk.Base().AutogenIncludeDir; + BuildFile += '/'; + BuildFile += rel; + } else { + BuildFile = wrk.Base().AbsoluteBuildPath(rel); + } + } + + if (UpdateRequired(wrk)) { + GenerateMoc(wrk); + } +} + +bool cmQtAutoGeneratorMocUic::JobMocT::UpdateRequired(WorkerT& wrk) +{ + bool const verbose = wrk.Gen().Log().Verbose(); + + // Test if the build file exists + if (!wrk.FileSys().FileExists(BuildFile)) { + if (verbose) { + std::string reason = "Generating "; + reason += Quoted(BuildFile); + reason += " from its source file "; + reason += Quoted(SourceFile); + reason += " because it doesn't exist"; + wrk.LogInfo(GeneratorT::MOC, reason); + } + return true; + } + + // Test if any setting changed + if (wrk.Moc().SettingsChanged) { + if (verbose) { + std::string reason = "Generating "; + reason += Quoted(BuildFile); + reason += " from "; + reason += Quoted(SourceFile); + reason += " because the MOC settings changed"; + wrk.LogInfo(GeneratorT::MOC, reason); + } + return true; + } + + // Test if the moc_predefs file is newer + if (!wrk.Moc().PredefsFileAbs.empty()) { + bool isOlder = false; + { + std::string error; + isOlder = wrk.FileSys().FileIsOlderThan( + BuildFile, wrk.Moc().PredefsFileAbs, &error); + if (!isOlder && !error.empty()) { + wrk.LogError(GeneratorT::MOC, error); + return false; + } + } + if (isOlder) { + if (verbose) { + std::string reason = "Generating "; + reason += Quoted(BuildFile); + reason += " because it's older than: "; + reason += Quoted(wrk.Moc().PredefsFileAbs); + wrk.LogInfo(GeneratorT::MOC, reason); + } + return true; + } + } + + // Test if the source file is newer + { + bool isOlder = false; + { + std::string error; + isOlder = wrk.FileSys().FileIsOlderThan(BuildFile, SourceFile, &error); + if (!isOlder && !error.empty()) { + wrk.LogError(GeneratorT::MOC, error); + return false; + } + } + if (isOlder) { + if (verbose) { + std::string reason = "Generating "; + reason += Quoted(BuildFile); + reason += " because it's older than its source file "; + reason += Quoted(SourceFile); + wrk.LogInfo(GeneratorT::MOC, reason); + } + return true; + } + } + + // Test if a dependency file is newer + { + // Read dependencies on demand + if (!DependsValid) { + std::string content; + { + std::string error; + if (!wrk.FileSys().FileRead(content, SourceFile, &error)) { + std::string emsg = "Could not read file\n "; + emsg += Quoted(SourceFile); + emsg += "\nrequired by moc include "; + emsg += Quoted(IncludeString); + emsg += " in\n "; + emsg += Quoted(IncluderFile); + emsg += ".\n"; + emsg += error; + wrk.LogError(GeneratorT::MOC, emsg); + return false; + } + } + FindDependencies(wrk, content); + } + // Check dependency timestamps + std::string error; + std::string sourceDir = SubDirPrefix(SourceFile); + for (std::string const& depFileRel : Depends) { + std::string depFileAbs = + wrk.Moc().FindIncludedFile(sourceDir, depFileRel); + if (!depFileAbs.empty()) { + if (wrk.FileSys().FileIsOlderThan(BuildFile, depFileAbs, &error)) { + if (verbose) { + std::string reason = "Generating "; + reason += Quoted(BuildFile); + reason += " from "; + reason += Quoted(SourceFile); + reason += " because it is older than it's dependency file "; + reason += Quoted(depFileAbs); + wrk.LogInfo(GeneratorT::MOC, reason); + } + return true; + } + if (!error.empty()) { + wrk.LogError(GeneratorT::MOC, error); + return false; + } + } else { + std::string message = "Could not find dependency file "; + message += Quoted(depFileRel); + wrk.LogFileWarning(GeneratorT::MOC, SourceFile, message); + } + } + } + + return false; +} + +void cmQtAutoGeneratorMocUic::JobMocT::GenerateMoc(WorkerT& wrk) +{ + // Make sure the parent directory exists + if (wrk.FileSys().MakeParentDirectory(GeneratorT::MOC, BuildFile)) { + // Compose moc command + std::vector<std::string> cmd; + cmd.push_back(wrk.Moc().Executable); + // Add options + cmd.insert(cmd.end(), wrk.Moc().AllOptions.begin(), + wrk.Moc().AllOptions.end()); + // Add predefs include + if (!wrk.Moc().PredefsFileAbs.empty()) { + cmd.push_back("--include"); + cmd.push_back(wrk.Moc().PredefsFileAbs); + } + cmd.push_back("-o"); + cmd.push_back(BuildFile); + cmd.push_back(SourceFile); + + // Execute moc command + ProcessResultT result; + if (wrk.RunProcess(GeneratorT::MOC, result, cmd)) { + // Moc command success + if (IncludeString.empty()) { + // Notify the generator that a not included file changed + wrk.Gen().ParallelMocAutoUpdated(); + } + } else { + // Moc command failed + { + std::string emsg = "The moc process failed to compile\n "; + emsg += Quoted(SourceFile); + emsg += "\ninto\n "; + emsg += Quoted(BuildFile); + emsg += ".\n"; + emsg += result.ErrorMessage; + wrk.LogCommandError(GeneratorT::MOC, emsg, cmd, result.StdOut); + } + wrk.FileSys().FileRemove(BuildFile); + } + } +} + +void cmQtAutoGeneratorMocUic::JobUicT::Process(WorkerT& wrk) +{ + // Compute build file name + BuildFile = wrk.Base().AutogenIncludeDir; + BuildFile += '/'; + BuildFile += IncludeString; + + if (UpdateRequired(wrk)) { + GenerateUic(wrk); + } +} + +bool cmQtAutoGeneratorMocUic::JobUicT::UpdateRequired(WorkerT& wrk) +{ + bool const verbose = wrk.Gen().Log().Verbose(); + + // Test if the build file exists + if (!wrk.FileSys().FileExists(BuildFile)) { + if (verbose) { + std::string reason = "Generating "; + reason += Quoted(BuildFile); + reason += " from its source file "; + reason += Quoted(SourceFile); + reason += " because it doesn't exist"; + wrk.LogInfo(GeneratorT::UIC, reason); + } + return true; + } + + // Test if the uic settings changed + if (wrk.Uic().SettingsChanged) { + if (verbose) { + std::string reason = "Generating "; + reason += Quoted(BuildFile); + reason += " from "; + reason += Quoted(SourceFile); + reason += " because the UIC settings changed"; + wrk.LogInfo(GeneratorT::UIC, reason); + } + return true; + } + + // Test if the source file is newer + { + bool isOlder = false; + { + std::string error; + isOlder = wrk.FileSys().FileIsOlderThan(BuildFile, SourceFile, &error); + if (!isOlder && !error.empty()) { + wrk.LogError(GeneratorT::UIC, error); + return false; + } + } + if (isOlder) { + if (verbose) { + std::string reason = "Generating "; + reason += Quoted(BuildFile); + reason += " because it's older than its source file "; + reason += Quoted(SourceFile); + wrk.LogInfo(GeneratorT::UIC, reason); + } + return true; + } + } + + return false; +} + +void cmQtAutoGeneratorMocUic::JobUicT::GenerateUic(WorkerT& wrk) +{ + // Make sure the parent directory exists + if (wrk.FileSys().MakeParentDirectory(GeneratorT::UIC, BuildFile)) { + // Compose uic command + std::vector<std::string> cmd; + cmd.push_back(wrk.Uic().Executable); + { + std::vector<std::string> allOpts = wrk.Uic().TargetOptions; + auto optionIt = wrk.Uic().Options.find(SourceFile); + if (optionIt != wrk.Uic().Options.end()) { + UicMergeOptions(allOpts, optionIt->second, + (wrk.Base().QtVersionMajor == 5)); + } + cmd.insert(cmd.end(), allOpts.begin(), allOpts.end()); + } + cmd.push_back("-o"); + cmd.push_back(BuildFile); + cmd.push_back(SourceFile); + + ProcessResultT result; + if (wrk.RunProcess(GeneratorT::UIC, result, cmd)) { + // Success + } else { + // Command failed + { + std::string emsg = "The uic process failed to compile\n "; + emsg += Quoted(SourceFile); + emsg += "\ninto\n "; + emsg += Quoted(BuildFile); + emsg += "\nincluded by\n "; + emsg += Quoted(IncluderFile); + emsg += ".\n"; + emsg += result.ErrorMessage; + wrk.LogCommandError(GeneratorT::UIC, emsg, cmd, result.StdOut); + } + wrk.FileSys().FileRemove(BuildFile); + } + } +} + +void cmQtAutoGeneratorMocUic::JobDeleterT::operator()(JobT* job) +{ + delete job; +} + +cmQtAutoGeneratorMocUic::WorkerT::WorkerT(cmQtAutoGeneratorMocUic* gen, + uv_loop_t* uvLoop) + : Gen_(gen) +{ + // Initialize uv asynchronous callback for process starting + ProcessRequest_.init(*uvLoop, &WorkerT::UVProcessStart, this); + // Start thread + Thread_ = std::thread(&WorkerT::Loop, this); +} + +cmQtAutoGeneratorMocUic::WorkerT::~WorkerT() +{ + // Join thread + if (Thread_.joinable()) { + Thread_.join(); + } +} + +void cmQtAutoGeneratorMocUic::WorkerT::LogInfo( + GeneratorT genType, std::string const& message) const +{ + return Log().Info(genType, message); +} + +void cmQtAutoGeneratorMocUic::WorkerT::LogWarning( + GeneratorT genType, std::string const& message) const +{ + return Log().Warning(genType, message); +} + +void cmQtAutoGeneratorMocUic::WorkerT::LogFileWarning( + GeneratorT genType, std::string const& filename, + std::string const& message) const +{ + return Log().WarningFile(genType, filename, message); +} + +void cmQtAutoGeneratorMocUic::WorkerT::LogError( + GeneratorT genType, std::string const& message) const +{ + Gen().ParallelRegisterJobError(); + Log().Error(genType, message); +} + +void cmQtAutoGeneratorMocUic::WorkerT::LogFileError( + GeneratorT genType, std::string const& filename, + std::string const& message) const +{ + Gen().ParallelRegisterJobError(); + Log().ErrorFile(genType, filename, message); +} + +void cmQtAutoGeneratorMocUic::WorkerT::LogCommandError( + GeneratorT genType, std::string const& message, + std::vector<std::string> const& command, std::string const& output) const +{ + Gen().ParallelRegisterJobError(); + Log().ErrorCommand(genType, message, command, output); +} + +bool cmQtAutoGeneratorMocUic::WorkerT::RunProcess( + GeneratorT genType, ProcessResultT& result, + std::vector<std::string> const& command) +{ + if (command.empty()) { + return false; + } + + // Create process instance + { + std::lock_guard<std::mutex> lock(ProcessMutex_); + Process_ = cm::make_unique<ReadOnlyProcessT>(); + Process_->setup(&result, true, command, Gen().Base().AutogenBuildDir); + } + + // Send asynchronous process start request to libuv loop + ProcessRequest_.send(); + + // Log command + if (this->Log().Verbose()) { + std::string msg = "Running command:\n"; + msg += QuotedCommand(command); + msg += '\n'; + this->LogInfo(genType, msg); + } + + // Wait until the process has been finished and destroyed + { + std::unique_lock<std::mutex> ulock(ProcessMutex_); + while (Process_) { + ProcessCondition_.wait(ulock); + } + } + return !result.error(); +} + +void cmQtAutoGeneratorMocUic::WorkerT::Loop() +{ + while (true) { + Gen().WorkerSwapJob(JobHandle_); + if (JobHandle_) { + JobHandle_->Process(*this); + } else { + break; + } + } +} + +void cmQtAutoGeneratorMocUic::WorkerT::UVProcessStart(uv_async_t* handle) +{ + auto& wrk = *reinterpret_cast<WorkerT*>(handle->data); + { + std::lock_guard<std::mutex> lock(wrk.ProcessMutex_); + if (wrk.Process_ && !wrk.Process_->IsStarted()) { + wrk.Process_->start(handle->loop, + std::bind(&WorkerT::UVProcessFinished, &wrk)); + } + } +} + +void cmQtAutoGeneratorMocUic::WorkerT::UVProcessFinished() +{ + { + std::lock_guard<std::mutex> lock(ProcessMutex_); + if (Process_ && Process_->IsFinished()) { + Process_.reset(); + } + } + // Notify idling thread + ProcessCondition_.notify_one(); +} + +cmQtAutoGeneratorMocUic::cmQtAutoGeneratorMocUic() + : Base_(&FileSys()) + , Moc_(&FileSys()) + , Stage_(StageT::SETTINGS_READ) + , JobsRemain_(0) + , JobError_(false) + , JobThreadsAbort_(false) + , MocAutoFileUpdated_(false) +{ + // Precompile regular expressions + Moc_.RegExpInclude.compile( + "(^|\n)[ \t]*#[ \t]*include[ \t]+" + "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]"); + Uic_.RegExpInclude.compile("(^|\n)[ \t]*#[ \t]*include[ \t]+" + "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]"); + + // Initialize libuv asynchronous iteration request + UVRequest().init(*UVLoop(), &cmQtAutoGeneratorMocUic::UVPollStage, this); +} + +cmQtAutoGeneratorMocUic::~cmQtAutoGeneratorMocUic() +{ +} + +bool cmQtAutoGeneratorMocUic::Init(cmMakefile* makefile) +{ + // -- Meta + Base_.HeaderExtensions = makefile->GetCMakeInstance()->GetHeaderExtensions(); + + // Utility lambdas + auto InfoGet = [makefile](const char* key) { + return makefile->GetSafeDefinition(key); + }; + auto InfoGetBool = [makefile](const char* key) { + return makefile->IsOn(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 InfoGetLists = + [makefile](const char* key) -> std::vector<std::vector<std::string>> { + std::vector<std::vector<std::string>> lists; + { + std::string const value = makefile->GetSafeDefinition(key); + std::string::size_type pos = 0; + while (pos < value.size()) { + std::string::size_type next = value.find(ListSep, pos); + std::string::size_type length = + (next != std::string::npos) ? next - pos : value.size() - pos; + // Remove enclosing braces + if (length >= 2) { + std::string::const_iterator itBeg = value.begin() + (pos + 1); + std::string::const_iterator itEnd = itBeg + (length - 2); + { + std::string subValue(itBeg, itEnd); + std::vector<std::string> list; + cmSystemTools::ExpandListArgument(subValue, list); + lists.push_back(std::move(list)); + } + } + pos += length; + pos += ListSep.size(); + } + } + return lists; + }; + auto InfoGetConfig = [makefile, this](const char* key) -> std::string { + const char* valueConf = nullptr; + { + std::string keyConf = key; + keyConf += '_'; + keyConf += InfoConfig(); + 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(InfoFile().c_str())) { + Log().ErrorFile(GeneratorT::GEN, InfoFile(), "File processing failed"); + return false; + } + + // -- Meta + Base_.MultiConfig = InfoGetBool("AM_MULTI_CONFIG"); + { + unsigned long num = Base_.NumThreads; + if (cmSystemTools::StringToULong(InfoGet("AM_PARALLEL"), &num)) { + num = std::max<unsigned long>(num, 1); + num = std::min<unsigned long>(num, ParallelMax); + Base_.NumThreads = static_cast<unsigned int>(num); + } + } + + // - Files and directories + Base_.ProjectSourceDir = InfoGet("AM_CMAKE_SOURCE_DIR"); + Base_.ProjectBinaryDir = InfoGet("AM_CMAKE_BINARY_DIR"); + Base_.CurrentSourceDir = InfoGet("AM_CMAKE_CURRENT_SOURCE_DIR"); + Base_.CurrentBinaryDir = InfoGet("AM_CMAKE_CURRENT_BINARY_DIR"); + Base_.IncludeProjectDirsBefore = + InfoGetBool("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE"); + Base_.AutogenBuildDir = InfoGet("AM_BUILD_DIR"); + if (Base_.AutogenBuildDir.empty()) { + Log().ErrorFile(GeneratorT::GEN, InfoFile(), + "Autogen build directory missing"); + return false; + } + // include directory + { + std::string dirRel = InfoGetConfig("AM_INCLUDE_DIR"); + if (dirRel.empty()) { + Log().ErrorFile(GeneratorT::GEN, InfoFile(), + "Autogen include directory missing"); + return false; + } + Base_.AutogenIncludeDir = Base_.AbsoluteBuildPath(dirRel); + } + + // - Files + SettingsFile_ = InfoGetConfig("AM_SETTINGS_FILE"); + if (SettingsFile_.empty()) { + Log().ErrorFile(GeneratorT::GEN, InfoFile(), "Settings file name missing"); + return false; + } + + // - Qt environment + { + unsigned long qtv = Base_.QtVersionMajor; + if (cmSystemTools::StringToULong(InfoGet("AM_QT_VERSION_MAJOR"), &qtv)) { + Base_.QtVersionMajor = static_cast<unsigned int>(qtv); + } + } + + // - Moc + Moc_.Executable = InfoGet("AM_QT_MOC_EXECUTABLE"); + Moc_.Enabled = !Moc().Executable.empty(); + if (Moc().Enabled) { + { + auto lst = InfoGetList("AM_MOC_SKIP"); + Moc_.SkipList.insert(lst.begin(), lst.end()); + } + Moc_.Definitions = InfoGetConfigList("AM_MOC_DEFINITIONS"); +#ifdef _WIN32 + { + std::string win32("WIN32"); + auto itB = Moc().Definitions.cbegin(); + auto itE = Moc().Definitions.cend(); + if (std::find(itB, itE, win32) == itE) { + Moc_.Definitions.emplace_back(std::move(win32)); + } + } +#endif + Moc_.IncludePaths = InfoGetConfigList("AM_MOC_INCLUDES"); + Moc_.Options = InfoGetList("AM_MOC_OPTIONS"); + Moc_.RelaxedMode = InfoGetBool("AM_MOC_RELAXED_MODE"); + for (std::string const& item : InfoGetList("AM_MOC_MACRO_NAMES")) { + Moc_.MacroFilters.emplace_back( + item, ("[\n][ \t]*{?[ \t]*" + item).append("[^a-zA-Z0-9_]")); + } + { + auto pushFilter = [this](std::string const& key, std::string const& exp, + std::string& error) { + if (!key.empty()) { + if (!exp.empty()) { + Moc_.DependFilters.push_back(KeyExpT()); + KeyExpT& filter(Moc_.DependFilters.back()); + if (filter.Exp.compile(exp)) { + filter.Key = key; + } else { + error = "Regular expression compiling failed"; + } + } else { + error = "Regular expression is empty"; + } + } else { + error = "Key is empty"; + } + if (!error.empty()) { + error = ("AUTOMOC_DEPEND_FILTERS: " + error); + error += "\n"; + error += " Key: "; + error += Quoted(key); + error += "\n"; + error += " Exp: "; + error += Quoted(exp); + error += "\n"; + } + }; + + std::string error; + // Insert default filter for Q_PLUGIN_METADATA + if (Base().QtVersionMajor != 4) { + pushFilter("Q_PLUGIN_METADATA", "[\n][ \t]*Q_PLUGIN_METADATA[ \t]*\\(" + "[^\\)]*FILE[ \t]*\"([^\"]+)\"", + error); + } + // Insert user defined dependency filters + { + std::vector<std::string> flts = InfoGetList("AM_MOC_DEPEND_FILTERS"); + if ((flts.size() % 2) == 0) { + for (std::vector<std::string>::iterator itC = flts.begin(), + itE = flts.end(); + itC != itE; itC += 2) { + pushFilter(*itC, *(itC + 1), error); + if (!error.empty()) { + break; + } + } + } else { + Log().ErrorFile( + GeneratorT::MOC, InfoFile(), + "AUTOMOC_DEPEND_FILTERS list size is not a multiple of 2"); + return false; + } + } + if (!error.empty()) { + Log().ErrorFile(GeneratorT::MOC, InfoFile(), error); + return false; + } + } + Moc_.PredefsCmd = InfoGetList("AM_MOC_PREDEFS_CMD"); + // Install moc predefs job + if (!Moc().PredefsCmd.empty()) { + JobQueues_.MocPredefs.emplace_back(new JobMocPredefsT()); + } + } + + // - Uic + Uic_.Executable = InfoGet("AM_QT_UIC_EXECUTABLE"); + Uic_.Enabled = !Uic().Executable.empty(); + if (Uic().Enabled) { + { + auto lst = InfoGetList("AM_UIC_SKIP"); + Uic_.SkipList.insert(lst.begin(), lst.end()); + } + Uic_.SearchPaths = InfoGetList("AM_UIC_SEARCH_PATHS"); + Uic_.TargetOptions = InfoGetConfigList("AM_UIC_TARGET_OPTIONS"); + { + auto sources = InfoGetList("AM_UIC_OPTIONS_FILES"); + auto options = InfoGetLists("AM_UIC_OPTIONS_OPTIONS"); + // Compare list sizes + if (sources.size() != options.size()) { + std::ostringstream ost; + ost << "files/options lists sizes missmatch (" << sources.size() << "/" + << options.size() << ")"; + Log().ErrorFile(GeneratorT::UIC, InfoFile(), ost.str()); + return false; + } + auto fitEnd = sources.cend(); + auto fit = sources.begin(); + auto oit = options.begin(); + while (fit != fitEnd) { + Uic_.Options[*fit] = std::move(*oit); + ++fit; + ++oit; + } + } + } + + // Initialize source file jobs + { + std::hash<std::string> stringHash; + std::set<std::size_t> uniqueHeaders; + + // Add header jobs + for (std::string& hdr : InfoGetList("AM_HEADERS")) { + const bool moc = !Moc().skipped(hdr); + const bool uic = !Uic().skipped(hdr); + if ((moc || uic) && uniqueHeaders.emplace(stringHash(hdr)).second) { + JobQueues_.Headers.emplace_back( + new JobParseT(std::move(hdr), moc, uic, true)); + } + } + // Add source jobs + { + std::vector<std::string> sources = InfoGetList("AM_SOURCES"); + // Add header(s) for the source file + for (std::string& src : sources) { + const bool srcMoc = !Moc().skipped(src); + const bool srcUic = !Uic().skipped(src); + if (!srcMoc && !srcUic) { + continue; + } + // Search for the default header file and a private header + { + std::array<std::string, 2> bases; + bases[0] = SubDirPrefix(src); + bases[0] += cmSystemTools::GetFilenameWithoutLastExtension(src); + bases[1] = bases[0]; + bases[1] += "_p"; + for (std::string const& headerBase : bases) { + std::string header; + if (Base().FindHeader(header, headerBase)) { + const bool moc = srcMoc && !Moc().skipped(header); + const bool uic = srcUic && !Uic().skipped(header); + if ((moc || uic) && + uniqueHeaders.emplace(stringHash(header)).second) { + JobQueues_.Headers.emplace_back( + new JobParseT(std::move(header), moc, uic, true)); + } + } + } + } + // Add source job + JobQueues_.Sources.emplace_back( + new JobParseT(std::move(src), srcMoc, srcUic)); + } + } + } + + // Init derived information + // ------------------------ + + // Init file path checksum generator + Base_.FilePathChecksum.setupParentDirs( + Base().CurrentSourceDir, Base().CurrentBinaryDir, Base().ProjectSourceDir, + Base().ProjectBinaryDir); + + // Moc variables + if (Moc().Enabled) { + // Mocs compilation file + Moc_.CompFileAbs = Base().AbsoluteBuildPath("mocs_compilation.cpp"); + + // Moc predefs file + if (!Moc_.PredefsCmd.empty()) { + Moc_.PredefsFileRel = "moc_predefs"; + if (Base_.MultiConfig) { + Moc_.PredefsFileRel += '_'; + Moc_.PredefsFileRel += InfoConfig(); + } + Moc_.PredefsFileRel += ".h"; + Moc_.PredefsFileAbs = Base_.AbsoluteBuildPath(Moc().PredefsFileRel); + } + + // Sort include directories on demand + if (Base().IncludeProjectDirsBefore) { + // Move strings to temporary list + std::list<std::string> includes; + includes.insert(includes.end(), Moc().IncludePaths.begin(), + Moc().IncludePaths.end()); + Moc_.IncludePaths.clear(); + Moc_.IncludePaths.reserve(includes.size()); + // Append project directories only + { + std::array<std::string const*, 2> const movePaths = { + { &Base().ProjectBinaryDir, &Base().ProjectSourceDir } + }; + for (std::string const* ppath : movePaths) { + std::list<std::string>::iterator it = includes.begin(); + while (it != includes.end()) { + std::string const& path = *it; + if (cmSystemTools::StringStartsWith(path, ppath->c_str())) { + Moc_.IncludePaths.push_back(path); + it = includes.erase(it); + } else { + ++it; + } + } + } + } + // Append remaining directories + Moc_.IncludePaths.insert(Moc_.IncludePaths.end(), includes.begin(), + includes.end()); + } + // Compose moc includes list + { + std::set<std::string> frameworkPaths; + for (std::string const& path : Moc().IncludePaths) { + Moc_.Includes.push_back("-I" + path); + // Extract framework path + if (cmHasLiteralSuffix(path, ".framework/Headers")) { + // Go up twice to get to the framework root + std::vector<std::string> pathComponents; + cmSystemTools::SplitPath(path, pathComponents); + std::string frameworkPath = cmSystemTools::JoinPath( + pathComponents.begin(), pathComponents.end() - 2); + frameworkPaths.insert(frameworkPath); + } + } + // Append framework includes + for (std::string const& path : frameworkPaths) { + Moc_.Includes.push_back("-F"); + Moc_.Includes.push_back(path); + } + } + // Setup single list with all options + { + // Add includes + Moc_.AllOptions.insert(Moc_.AllOptions.end(), Moc().Includes.begin(), + Moc().Includes.end()); + // Add definitions + for (std::string const& def : Moc().Definitions) { + Moc_.AllOptions.push_back("-D" + def); + } + // Add options + Moc_.AllOptions.insert(Moc_.AllOptions.end(), Moc().Options.begin(), + Moc().Options.end()); + } + } + + return true; +} + +bool cmQtAutoGeneratorMocUic::Process() +{ + // Run libuv event loop + UVRequest().send(); + if (uv_run(UVLoop(), UV_RUN_DEFAULT) == 0) { + if (JobError_) { + return false; + } + } else { + return false; + } + return true; +} + +void cmQtAutoGeneratorMocUic::UVPollStage(uv_async_t* handle) +{ + reinterpret_cast<cmQtAutoGeneratorMocUic*>(handle->data)->PollStage(); +} + +void cmQtAutoGeneratorMocUic::PollStage() +{ + switch (Stage_) { + case StageT::SETTINGS_READ: + SettingsFileRead(); + SetStage(StageT::CREATE_DIRECTORIES); + break; + case StageT::CREATE_DIRECTORIES: + CreateDirectories(); + SetStage(StageT::PARSE_SOURCES); + break; + case StageT::PARSE_SOURCES: + if (ThreadsStartJobs(JobQueues_.Sources)) { + SetStage(StageT::PARSE_HEADERS); + } + break; + case StageT::PARSE_HEADERS: + if (ThreadsStartJobs(JobQueues_.Headers)) { + SetStage(StageT::MOC_PREDEFS); + } + break; + case StageT::MOC_PREDEFS: + if (ThreadsStartJobs(JobQueues_.MocPredefs)) { + SetStage(StageT::MOC_PROCESS); + } + break; + case StageT::MOC_PROCESS: + if (ThreadsStartJobs(JobQueues_.Moc)) { + SetStage(StageT::MOCS_COMPILATION); + } + break; + case StageT::MOCS_COMPILATION: + if (ThreadsJobsDone()) { + MocGenerateCompilation(); + SetStage(StageT::UIC_PROCESS); + } + break; + case StageT::UIC_PROCESS: + if (ThreadsStartJobs(JobQueues_.Uic)) { + SetStage(StageT::SETTINGS_WRITE); + } + break; + case StageT::SETTINGS_WRITE: + SettingsFileWrite(); + SetStage(StageT::FINISH); + break; + case StageT::FINISH: + if (ThreadsJobsDone()) { + // Clear all libuv handles + ThreadsStop(); + UVRequest().reset(); + // Set highest END stage manually + Stage_ = StageT::END; + } + break; + case StageT::END: + break; + } +} + +void cmQtAutoGeneratorMocUic::SetStage(StageT stage) +{ + if (JobError_) { + stage = StageT::FINISH; + } + // Only allow to increase the stage + if (Stage_ < stage) { + Stage_ = stage; + UVRequest().send(); + } +} + +void cmQtAutoGeneratorMocUic::SettingsFileRead() +{ + // Compose current settings strings + { + cmCryptoHash crypt(cmCryptoHash::AlgoSHA256); + std::string const sep(" ~~~ "); + if (Moc_.Enabled) { + std::string str; + str += Moc().Executable; + str += sep; + str += cmJoin(Moc().AllOptions, ";"); + str += sep; + str += Base().IncludeProjectDirsBefore ? "TRUE" : "FALSE"; + str += sep; + str += cmJoin(Moc().PredefsCmd, ";"); + str += sep; + SettingsStringMoc_ = crypt.HashString(str); + } + if (Uic().Enabled) { + std::string str; + str += Uic().Executable; + str += sep; + str += cmJoin(Uic().TargetOptions, ";"); + for (const auto& item : Uic().Options) { + str += sep; + str += item.first; + str += sep; + str += cmJoin(item.second, ";"); + } + str += sep; + SettingsStringUic_ = crypt.HashString(str); + } + } + + // Read old settings and compare + { + std::string content; + if (FileSys().FileRead(content, SettingsFile_)) { + if (Moc().Enabled) { + if (SettingsStringMoc_ != SettingsFind(content, "moc")) { + Moc_.SettingsChanged = true; + } + } + if (Uic().Enabled) { + if (SettingsStringUic_ != SettingsFind(content, "uic")) { + Uic_.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 (Moc().SettingsChanged || Uic().SettingsChanged) { + FileSys().FileRemove(SettingsFile_); + } + } else { + // Settings file read failed + if (Moc().Enabled) { + Moc_.SettingsChanged = true; + } + if (Uic().Enabled) { + Uic_.SettingsChanged = true; + } + } + } +} + +void cmQtAutoGeneratorMocUic::SettingsFileWrite() +{ + std::lock_guard<std::mutex> jobsLock(JobsMutex_); + // Only write if any setting changed + if (!JobError_ && (Moc().SettingsChanged || Uic().SettingsChanged)) { + if (Log().Verbose()) { + Log().Info(GeneratorT::GEN, + "Writing settings file " + Quoted(SettingsFile_)); + } + // Compose settings file content + std::string content; + { + auto SettingAppend = [&content](const char* key, + std::string const& value) { + if (!value.empty()) { + content += key; + content += ':'; + content += value; + content += '\n'; + } + }; + SettingAppend("moc", SettingsStringMoc_); + SettingAppend("uic", SettingsStringUic_); + } + // Write settings file + if (!FileSys().FileWrite(GeneratorT::GEN, SettingsFile_, content)) { + Log().ErrorFile(GeneratorT::GEN, SettingsFile_, + "Settings file writing failed"); + // Remove old settings file to trigger a full rebuild on the next run + FileSys().FileRemove(SettingsFile_); + RegisterJobError(); + } + } +} + +void cmQtAutoGeneratorMocUic::CreateDirectories() +{ + // Create AUTOGEN include directory + if (!FileSys().MakeDirectory(GeneratorT::GEN, Base().AutogenIncludeDir)) { + RegisterJobError(); + } +} + +bool cmQtAutoGeneratorMocUic::ThreadsStartJobs(JobQueueT& queue) +{ + bool done = false; + std::size_t queueSize = queue.size(); + + // Change the active queue + { + std::lock_guard<std::mutex> jobsLock(JobsMutex_); + // Check if there are still unfinished jobs from the previous queue + if (JobsRemain_ == 0) { + if (!JobThreadsAbort_) { + JobQueue_.swap(queue); + JobsRemain_ = queueSize; + } else { + // Abort requested + queue.clear(); + queueSize = 0; + } + done = true; + } + } + + if (done && (queueSize != 0)) { + // Start new threads on demand + if (Workers_.empty()) { + Workers_.resize(Base().NumThreads); + for (auto& item : Workers_) { + item = cm::make_unique<WorkerT>(this, UVLoop()); + } + } else { + // Notify threads + if (queueSize == 1) { + JobsConditionRead_.notify_one(); + } else { + JobsConditionRead_.notify_all(); + } + } + } + + return done; +} + +void cmQtAutoGeneratorMocUic::ThreadsStop() +{ + if (!Workers_.empty()) { + // Clear all jobs + { + std::lock_guard<std::mutex> jobsLock(JobsMutex_); + JobThreadsAbort_ = true; + JobsRemain_ -= JobQueue_.size(); + JobQueue_.clear(); + + JobQueues_.Sources.clear(); + JobQueues_.Headers.clear(); + JobQueues_.MocPredefs.clear(); + JobQueues_.Moc.clear(); + JobQueues_.Uic.clear(); + } + // Wake threads + JobsConditionRead_.notify_all(); + // Join and clear threads + Workers_.clear(); + } +} + +bool cmQtAutoGeneratorMocUic::ThreadsJobsDone() +{ + std::lock_guard<std::mutex> jobsLock(JobsMutex_); + return (JobsRemain_ == 0); +} + +void cmQtAutoGeneratorMocUic::WorkerSwapJob(JobHandleT& jobHandle) +{ + bool const jobProcessed(jobHandle); + if (jobProcessed) { + jobHandle.reset(nullptr); + } + { + std::unique_lock<std::mutex> jobsLock(JobsMutex_); + // Reduce the remaining job count and notify the libuv loop + // when all jobs are done + if (jobProcessed) { + --JobsRemain_; + if (JobsRemain_ == 0) { + UVRequest().send(); + } + } + // Wait for new jobs + while (!JobThreadsAbort_ && JobQueue_.empty()) { + JobsConditionRead_.wait(jobsLock); + } + // Try to pick up a new job handle + if (!JobThreadsAbort_ && !JobQueue_.empty()) { + jobHandle = std::move(JobQueue_.front()); + JobQueue_.pop_front(); + } + } +} + +void cmQtAutoGeneratorMocUic::ParallelRegisterJobError() +{ + std::lock_guard<std::mutex> jobsLock(JobsMutex_); + RegisterJobError(); +} + +// Private method that requires cmQtAutoGeneratorMocUic::JobsMutex_ to be +// locked +void cmQtAutoGeneratorMocUic::RegisterJobError() +{ + JobError_ = true; + if (!JobThreadsAbort_) { + JobThreadsAbort_ = true; + // Clear remaining jobs + if (JobsRemain_ != 0) { + JobsRemain_ -= JobQueue_.size(); + JobQueue_.clear(); + } + } +} + +bool cmQtAutoGeneratorMocUic::ParallelJobPushMoc(JobHandleT& jobHandle) +{ + std::lock_guard<std::mutex> jobsLock(JobsMutex_); + if (!JobThreadsAbort_) { + bool pushJobHandle = true; + // Do additional tests if this is an included moc job + const JobMocT& mocJob(static_cast<JobMocT&>(*jobHandle)); + if (!mocJob.IncludeString.empty()) { + // Register included moc file and look for collisions + MocIncludedFiles_.emplace(mocJob.SourceFile); + if (!MocIncludedStrings_.emplace(mocJob.IncludeString).second) { + // Another source file includes the same moc file! + for (const JobHandleT& otherHandle : JobQueues_.Moc) { + const JobMocT& otherJob(static_cast<JobMocT&>(*otherHandle)); + if (otherJob.IncludeString == mocJob.IncludeString) { + // Check if the same moc file would be generated from different + // source files which is an error. + if (otherJob.SourceFile != mocJob.SourceFile) { + // Include string collision + std::string error = "The two source files\n "; + error += Quoted(mocJob.IncluderFile); + error += " and\n "; + error += Quoted(otherJob.IncluderFile); + error += "\ncontain the the same moc include string "; + error += Quoted(mocJob.IncludeString); + error += "\nbut the moc file would be generated from different " + "source files\n "; + error += Quoted(mocJob.SourceFile); + error += " and\n "; + error += Quoted(otherJob.SourceFile); + error += ".\nConsider to\n" + "- not include the \"moc_<NAME>.cpp\" file\n" + "- add a directory prefix to a \"<NAME>.moc\" include " + "(e.g \"sub/<NAME>.moc\")\n" + "- rename the source file(s)\n"; + Log().Error(GeneratorT::MOC, error); + RegisterJobError(); + } + // Do not push this job in since the included moc file already + // gets generated by an other job. + pushJobHandle = false; + break; + } + } + } + } + // Push job on demand + if (pushJobHandle) { + JobQueues_.Moc.emplace_back(std::move(jobHandle)); + } + } + return !JobError_; +} + +bool cmQtAutoGeneratorMocUic::ParallelJobPushUic(JobHandleT& jobHandle) +{ + std::lock_guard<std::mutex> jobsLock(JobsMutex_); + if (!JobThreadsAbort_) { + bool pushJobHandle = true; + // Look for include collisions. + const JobUicT& uicJob(static_cast<JobUicT&>(*jobHandle)); + for (const JobHandleT& otherHandle : JobQueues_.Uic) { + const JobUicT& otherJob(static_cast<JobUicT&>(*otherHandle)); + if (otherJob.IncludeString == uicJob.IncludeString) { + // Check if the same uic file would be generated from different + // source files which would be an error. + if (otherJob.SourceFile != uicJob.SourceFile) { + // Include string collision + std::string error = "The two source files\n "; + error += Quoted(uicJob.IncluderFile); + error += " and\n "; + error += Quoted(otherJob.IncluderFile); + error += "\ncontain the the same uic include string "; + error += Quoted(uicJob.IncludeString); + error += "\nbut the uic file would be generated from different " + "source files\n "; + error += Quoted(uicJob.SourceFile); + error += " and\n "; + error += Quoted(otherJob.SourceFile); + error += + ".\nConsider to\n" + "- add a directory prefix to a \"ui_<NAME>.h\" include " + "(e.g \"sub/ui_<NAME>.h\")\n" + "- rename the <NAME>.ui file(s) and adjust the \"ui_<NAME>.h\" " + "include(s)\n"; + Log().Error(GeneratorT::UIC, error); + RegisterJobError(); + } + // Do not push this job in since the uic file already + // gets generated by an other job. + pushJobHandle = false; + break; + } + } + if (pushJobHandle) { + JobQueues_.Uic.emplace_back(std::move(jobHandle)); + } + } + return !JobError_; +} + +bool cmQtAutoGeneratorMocUic::ParallelMocIncluded( + std::string const& sourceFile) +{ + std::lock_guard<std::mutex> mocLock(JobsMutex_); + return (MocIncludedFiles_.find(sourceFile) != MocIncludedFiles_.end()); +} + +void cmQtAutoGeneratorMocUic::ParallelMocAutoRegister( + std::string const& mocFile) +{ + std::lock_guard<std::mutex> mocLock(JobsMutex_); + MocAutoFiles_.emplace(mocFile); +} + +void cmQtAutoGeneratorMocUic::ParallelMocAutoUpdated() +{ + std::lock_guard<std::mutex> mocLock(JobsMutex_); + MocAutoFileUpdated_ = true; +} + +void cmQtAutoGeneratorMocUic::MocGenerateCompilation() +{ + std::lock_guard<std::mutex> mocLock(JobsMutex_); + if (!JobError_ && Moc().Enabled) { + // Write mocs compilation build file + { + // Compose mocs compilation file content + std::string content = + "// This file is autogenerated. Changes will be overwritten.\n"; + if (MocAutoFiles_.empty()) { + // Placeholder content + content += "// No files found that require moc or the moc files are " + "included\n"; + content += "enum some_compilers { need_more_than_nothing };\n"; + } else { + // Valid content + char const sbeg = Base().MultiConfig ? '<' : '"'; + char const send = Base().MultiConfig ? '>' : '"'; + for (std::string const& mocfile : MocAutoFiles_) { + content += "#include "; + content += sbeg; + content += mocfile; + content += send; + content += '\n'; + } + } + + std::string const& compAbs = Moc().CompFileAbs; + if (FileSys().FileDiffers(compAbs, content)) { + // Actually write mocs compilation file + if (Log().Verbose()) { + Log().Info(GeneratorT::MOC, "Generating MOC compilation " + compAbs); + } + if (!FileSys().FileWrite(GeneratorT::MOC, compAbs, content)) { + Log().ErrorFile(GeneratorT::MOC, compAbs, + "mocs compilation file writing failed"); + RegisterJobError(); + return; + } + } else if (MocAutoFileUpdated_) { + // Only touch mocs compilation file + if (Log().Verbose()) { + Log().Info(GeneratorT::MOC, "Touching mocs compilation " + compAbs); + } + FileSys().Touch(compAbs); + } + } + // Write mocs compilation wrapper file + if (Base().MultiConfig) { + } + } +} diff --git a/Source/cmQtAutoGeneratorMocUic.h b/Source/cmQtAutoGeneratorMocUic.h new file mode 100644 index 0000000..696d5bd --- /dev/null +++ b/Source/cmQtAutoGeneratorMocUic.h @@ -0,0 +1,438 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmQtAutoGeneratorMocUic_h +#define cmQtAutoGeneratorMocUic_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include "cmFilePathChecksum.h" +#include "cmQtAutoGen.h" +#include "cmQtAutoGenerator.h" +#include "cmUVHandlePtr.h" +#include "cm_uv.h" +#include "cmsys/RegularExpression.hxx" + +#include <algorithm> +#include <condition_variable> +#include <cstddef> +#include <deque> +#include <map> +#include <memory> // IWYU pragma: keep +#include <mutex> +#include <set> +#include <string> +#include <thread> +#include <vector> + +class cmMakefile; + +// @brief AUTOMOC and AUTOUIC generator +class cmQtAutoGeneratorMocUic : public cmQtAutoGenerator +{ + CM_DISABLE_COPY(cmQtAutoGeneratorMocUic) +public: + cmQtAutoGeneratorMocUic(); + ~cmQtAutoGeneratorMocUic() override; + +public: + // -- Types + class WorkerT; + + /// @brief Search key plus regular expression pair + /// + struct KeyExpT + { + KeyExpT() = default; + + KeyExpT(const char* key, const char* exp) + : Key(key) + , Exp(exp) + { + } + + KeyExpT(std::string const& key, std::string const& exp) + : Key(key) + , Exp(exp) + { + } + + std::string Key; + cmsys::RegularExpression Exp; + }; + + /// @brief Common settings + /// + class BaseSettingsT + { + CM_DISABLE_COPY(BaseSettingsT) + public: + // -- Volatile methods + BaseSettingsT(FileSystem* fileSystem) + : MultiConfig(false) + , IncludeProjectDirsBefore(false) + , QtVersionMajor(4) + , NumThreads(1) + , FileSys(fileSystem) + { + } + + // -- Const methods + std::string AbsoluteBuildPath(std::string const& relativePath) const; + bool FindHeader(std::string& header, + std::string const& testBasePath) const; + + // -- Attributes + // - Config + bool MultiConfig; + bool IncludeProjectDirsBefore; + unsigned int QtVersionMajor; + unsigned int NumThreads; + // - Directories + std::string ProjectSourceDir; + std::string ProjectBinaryDir; + std::string CurrentSourceDir; + std::string CurrentBinaryDir; + std::string AutogenBuildDir; + std::string AutogenIncludeDir; + // - Files + cmFilePathChecksum FilePathChecksum; + std::vector<std::string> HeaderExtensions; + // - File system + FileSystem* FileSys; + }; + + /// @brief Moc settings + /// + class MocSettingsT + { + CM_DISABLE_COPY(MocSettingsT) + public: + MocSettingsT(FileSystem* fileSys) + : FileSys(fileSys) + { + } + + // -- Const methods + bool skipped(std::string const& fileName) const; + std::string FindMacro(std::string const& content) const; + std::string MacrosString() const; + std::string FindIncludedFile(std::string const& sourcePath, + std::string const& includeString) const; + void FindDependencies(std::string const& content, + std::set<std::string>& depends) const; + + // -- Attributes + bool Enabled = false; + bool SettingsChanged = false; + bool RelaxedMode = false; + std::string Executable; + std::string CompFileAbs; + std::string PredefsFileRel; + std::string PredefsFileAbs; + std::set<std::string> SkipList; + std::vector<std::string> IncludePaths; + std::vector<std::string> Includes; + std::vector<std::string> Definitions; + std::vector<std::string> Options; + std::vector<std::string> AllOptions; + std::vector<std::string> PredefsCmd; + std::vector<KeyExpT> DependFilters; + std::vector<KeyExpT> MacroFilters; + cmsys::RegularExpression RegExpInclude; + // - File system + FileSystem* FileSys; + }; + + /// @brief Uic settings + /// + class UicSettingsT + { + CM_DISABLE_COPY(UicSettingsT) + public: + UicSettingsT() = default; + // -- Const methods + bool skipped(std::string const& fileName) const; + + // -- Attributes + bool Enabled = false; + bool SettingsChanged = false; + std::string Executable; + std::set<std::string> SkipList; + std::vector<std::string> TargetOptions; + std::map<std::string, std::vector<std::string>> Options; + std::vector<std::string> SearchPaths; + cmsys::RegularExpression RegExpInclude; + }; + + /// @brief Abstract job class for threaded processing + /// + class JobT + { + CM_DISABLE_COPY(JobT) + public: + JobT() = default; + virtual ~JobT() = default; + // -- Abstract processing interface + virtual void Process(WorkerT& wrk) = 0; + }; + + /// @brief Deleter for classes derived from Job + /// + struct JobDeleterT + { + void operator()(JobT* job); + }; + + // Job management types + typedef std::unique_ptr<JobT, JobDeleterT> JobHandleT; + typedef std::deque<JobHandleT> JobQueueT; + + /// @brief Parse source job + /// + class JobParseT : public JobT + { + public: + JobParseT(std::string&& fileName, bool moc, bool uic, bool header = false) + : FileName(std::move(fileName)) + , AutoMoc(moc) + , AutoUic(uic) + , Header(header) + { + } + + private: + struct MetaT + { + std::string Content; + std::string FileDir; + std::string FileBase; + }; + + void Process(WorkerT& wrk) override; + bool ParseMocSource(WorkerT& wrk, MetaT const& meta); + bool ParseMocHeader(WorkerT& wrk, MetaT const& meta); + std::string MocStringHeaders(WorkerT& wrk, + std::string const& fileBase) const; + std::string MocFindIncludedHeader(WorkerT& wrk, + std::string const& includerDir, + std::string const& includeBase); + bool ParseUic(WorkerT& wrk, MetaT const& meta); + bool ParseUicInclude(WorkerT& wrk, MetaT const& meta, + std::string&& includeString); + std::string UicFindIncludedFile(WorkerT& wrk, MetaT const& meta, + std::string const& includeString); + + private: + std::string FileName; + bool AutoMoc = false; + bool AutoUic = false; + bool Header = false; + }; + + /// @brief Generate moc_predefs + /// + class JobMocPredefsT : public JobT + { + private: + void Process(WorkerT& wrk) override; + }; + + /// @brief Moc a file job + /// + class JobMocT : public JobT + { + public: + JobMocT(std::string&& sourceFile, std::string const& includerFile, + std::string&& includeString) + : SourceFile(std::move(sourceFile)) + , IncluderFile(includerFile) + , IncludeString(std::move(includeString)) + { + } + + void FindDependencies(WorkerT& wrk, std::string const& content); + + private: + void Process(WorkerT& wrk) override; + bool UpdateRequired(WorkerT& wrk); + void GenerateMoc(WorkerT& wrk); + + public: + std::string SourceFile; + std::string IncluderFile; + std::string IncludeString; + std::string BuildFile; + bool DependsValid = false; + std::set<std::string> Depends; + }; + + /// @brief Uic a file job + /// + class JobUicT : public JobT + { + public: + JobUicT(std::string&& sourceFile, std::string const& includerFile, + std::string&& includeString) + : SourceFile(std::move(sourceFile)) + , IncluderFile(includerFile) + , IncludeString(std::move(includeString)) + { + } + + private: + void Process(WorkerT& wrk) override; + bool UpdateRequired(WorkerT& wrk); + void GenerateUic(WorkerT& wrk); + + public: + std::string SourceFile; + std::string IncluderFile; + std::string IncludeString; + std::string BuildFile; + }; + + /// @brief Worker Thread + /// + class WorkerT + { + CM_DISABLE_COPY(WorkerT) + public: + WorkerT(cmQtAutoGeneratorMocUic* gen, uv_loop_t* uvLoop); + ~WorkerT(); + + // -- Const accessors + cmQtAutoGeneratorMocUic& Gen() const { return *Gen_; } + Logger& Log() const { return Gen_->Log(); } + FileSystem& FileSys() const { return Gen_->FileSys(); } + const BaseSettingsT& Base() const { return Gen_->Base(); } + const MocSettingsT& Moc() const { return Gen_->Moc(); } + const UicSettingsT& Uic() const { return Gen_->Uic(); } + + // -- Log info + void LogInfo(GeneratorT genType, std::string const& message) const; + // -- Log warning + void LogWarning(GeneratorT genType, std::string const& message) const; + void LogFileWarning(GeneratorT genType, std::string const& filename, + std::string const& message) const; + // -- Log error + void LogError(GeneratorT genType, std::string const& message) const; + void LogFileError(GeneratorT genType, std::string const& filename, + std::string const& message) const; + void LogCommandError(GeneratorT genType, std::string const& message, + std::vector<std::string> const& command, + std::string const& output) const; + + // -- External processes + /// @brief Verbose logging version + bool RunProcess(GeneratorT genType, ProcessResultT& result, + std::vector<std::string> const& command); + + private: + /// @brief Thread main loop + void Loop(); + + // -- Libuv callbacks + static void UVProcessStart(uv_async_t* handle); + void UVProcessFinished(); + + private: + // -- Generator + cmQtAutoGeneratorMocUic* Gen_; + // -- Job handle + JobHandleT JobHandle_; + // -- Process management + std::mutex ProcessMutex_; + cm::uv_async_ptr ProcessRequest_; + std::condition_variable ProcessCondition_; + std::unique_ptr<ReadOnlyProcessT> Process_; + // -- System thread + std::thread Thread_; + }; + + /// @brief Processing stage + enum class StageT + { + SETTINGS_READ, + CREATE_DIRECTORIES, + PARSE_SOURCES, + PARSE_HEADERS, + MOC_PREDEFS, + MOC_PROCESS, + MOCS_COMPILATION, + UIC_PROCESS, + SETTINGS_WRITE, + FINISH, + END + }; + + // -- Const settings interface + const BaseSettingsT& Base() const { return this->Base_; } + const MocSettingsT& Moc() const { return this->Moc_; } + const UicSettingsT& Uic() const { return this->Uic_; } + + // -- Worker thread interface + void WorkerSwapJob(JobHandleT& jobHandle); + // -- Parallel job processing interface + void ParallelRegisterJobError(); + bool ParallelJobPushMoc(JobHandleT& jobHandle); + bool ParallelJobPushUic(JobHandleT& jobHandle); + bool ParallelMocIncluded(std::string const& sourceFile); + void ParallelMocAutoRegister(std::string const& mocFile); + void ParallelMocAutoUpdated(); + +private: + // -- Abstract processing interface + bool Init(cmMakefile* makefile) override; + bool Process() override; + // -- Process stage + static void UVPollStage(uv_async_t* handle); + void PollStage(); + void SetStage(StageT stage); + // -- Settings file + void SettingsFileRead(); + void SettingsFileWrite(); + // -- Thread processing + bool ThreadsStartJobs(JobQueueT& queue); + bool ThreadsJobsDone(); + void ThreadsStop(); + void RegisterJobError(); + // -- Generation + void CreateDirectories(); + void MocGenerateCompilation(); + +private: + // -- Settings + BaseSettingsT Base_; + MocSettingsT Moc_; + UicSettingsT Uic_; + // -- Progress + StageT Stage_; + // -- Job queues + std::mutex JobsMutex_; + struct + { + JobQueueT Sources; + JobQueueT Headers; + JobQueueT MocPredefs; + JobQueueT Moc; + JobQueueT Uic; + } JobQueues_; + JobQueueT JobQueue_; + std::size_t volatile JobsRemain_; + bool volatile JobError_; + bool volatile JobThreadsAbort_; + std::condition_variable JobsConditionRead_; + // -- Moc meta + std::set<std::string> MocIncludedStrings_; + std::set<std::string> MocIncludedFiles_; + std::set<std::string> MocAutoFiles_; + bool volatile MocAutoFileUpdated_; + // -- Settings file + std::string SettingsFile_; + std::string SettingsStringMoc_; + std::string SettingsStringUic_; + // -- Threads and loops + std::vector<std::unique_ptr<WorkerT>> Workers_; +}; + +#endif diff --git a/Source/cmQtAutoGeneratorRcc.cxx b/Source/cmQtAutoGeneratorRcc.cxx new file mode 100644 index 0000000..2bf00f7 --- /dev/null +++ b/Source/cmQtAutoGeneratorRcc.cxx @@ -0,0 +1,638 @@ +/* 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 "cmSystemTools.h" +#include "cmUVHandlePtr.h" + +#include <functional> + +// -- Class methods + +cmQtAutoGeneratorRcc::cmQtAutoGeneratorRcc() + : MultiConfig_(false) + , SettingsChanged_(false) + , Stage_(StageT::SETTINGS_READ) + , Error_(false) + , Generate_(false) + , BuildFileChanged_(false) +{ + // Initialize libuv asynchronous iteration request + UVRequest().init(*UVLoop(), &cmQtAutoGeneratorRcc::UVPollStage, this); +} + +cmQtAutoGeneratorRcc::~cmQtAutoGeneratorRcc() +{ +} + +bool cmQtAutoGeneratorRcc::Init(cmMakefile* makefile) +{ + // -- Utility lambdas + auto InfoGet = [makefile](std::string const& key) { + return makefile->GetSafeDefinition(key); + }; + auto InfoGetList = + [makefile](std::string const& key) -> std::vector<std::string> { + std::vector<std::string> list; + cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition(key), list); + return list; + }; + auto InfoGetConfig = [makefile, + this](std::string const& key) -> std::string { + const char* valueConf = nullptr; + { + std::string keyConf = key; + keyConf += '_'; + keyConf += InfoConfig(); + valueConf = makefile->GetDefinition(keyConf); + } + if (valueConf == nullptr) { + valueConf = makefile->GetSafeDefinition(key); + } + return std::string(valueConf); + }; + auto InfoGetConfigList = + [&InfoGetConfig](std::string const& key) -> std::vector<std::string> { + std::vector<std::string> list; + cmSystemTools::ExpandListArgument(InfoGetConfig(key), list); + return list; + }; + + // -- Read info file + if (!makefile->ReadListFile(InfoFile().c_str())) { + Log().ErrorFile(GeneratorT::RCC, InfoFile(), "File processing failed"); + return false; + } + + // - Configurations + MultiConfig_ = makefile->IsOn("ARCC_MULTI_CONFIG"); + + // - Directories + AutogenBuildDir_ = InfoGet("ARCC_BUILD_DIR"); + if (AutogenBuildDir_.empty()) { + Log().ErrorFile(GeneratorT::RCC, InfoFile(), "Build directory empty"); + return false; + } + + IncludeDir_ = InfoGetConfig("ARCC_INCLUDE_DIR"); + if (IncludeDir_.empty()) { + Log().ErrorFile(GeneratorT::RCC, InfoFile(), "Include directory empty"); + return false; + } + + // - Rcc executable + RccExecutable_ = InfoGet("ARCC_RCC_EXECUTABLE"); + RccListOptions_ = InfoGetList("ARCC_RCC_LIST_OPTIONS"); + + // - Job + QrcFile_ = InfoGet("ARCC_SOURCE"); + QrcFileName_ = cmSystemTools::GetFilenameName(QrcFile_); + QrcFileDir_ = cmSystemTools::GetFilenamePath(QrcFile_); + RccPathChecksum_ = InfoGet("ARCC_OUTPUT_CHECKSUM"); + RccFileName_ = InfoGet("ARCC_OUTPUT_NAME"); + Options_ = InfoGetConfigList("ARCC_OPTIONS"); + Inputs_ = InfoGetList("ARCC_INPUTS"); + + // - Settings file + SettingsFile_ = InfoGetConfig("ARCC_SETTINGS_FILE"); + + // - Validity checks + if (SettingsFile_.empty()) { + Log().ErrorFile(GeneratorT::RCC, InfoFile(), "Settings file name missing"); + return false; + } + if (AutogenBuildDir_.empty()) { + Log().ErrorFile(GeneratorT::RCC, InfoFile(), + "Autogen build directory missing"); + return false; + } + if (RccExecutable_.empty()) { + Log().ErrorFile(GeneratorT::RCC, InfoFile(), "rcc executable missing"); + return false; + } + if (QrcFile_.empty()) { + Log().ErrorFile(GeneratorT::RCC, InfoFile(), "rcc input file missing"); + return false; + } + if (RccFileName_.empty()) { + Log().ErrorFile(GeneratorT::RCC, InfoFile(), "rcc output file missing"); + return false; + } + + // Init derived information + // ------------------------ + + RccFilePublic_ = AutogenBuildDir_; + RccFilePublic_ += '/'; + RccFilePublic_ += RccPathChecksum_; + RccFilePublic_ += '/'; + RccFilePublic_ += RccFileName_; + + // Compute rcc output file name + if (IsMultiConfig()) { + RccFileOutput_ = AutogenBuildDir_; + RccFileOutput_ += '/'; + RccFileOutput_ += IncludeDir_; + RccFileOutput_ += '/'; + RccFileOutput_ += MultiConfigOutput(); + } else { + RccFileOutput_ = RccFilePublic_; + } + + return true; +} + +bool cmQtAutoGeneratorRcc::Process() +{ + // Run libuv event loop + UVRequest().send(); + if (uv_run(UVLoop(), UV_RUN_DEFAULT) == 0) { + if (Error_) { + return false; + } + } else { + return false; + } + return true; +} + +void cmQtAutoGeneratorRcc::UVPollStage(uv_async_t* handle) +{ + reinterpret_cast<cmQtAutoGeneratorRcc*>(handle->data)->PollStage(); +} + +void cmQtAutoGeneratorRcc::PollStage() +{ + switch (Stage_) { + // -- Initialize + case StageT::SETTINGS_READ: + SettingsFileRead(); + SetStage(StageT::TEST_QRC_RCC_FILES); + break; + + // -- Change detection + case StageT::TEST_QRC_RCC_FILES: + if (TestQrcRccFiles()) { + SetStage(StageT::GENERATE); + } else { + SetStage(StageT::TEST_RESOURCES_READ); + } + break; + case StageT::TEST_RESOURCES_READ: + if (TestResourcesRead()) { + SetStage(StageT::TEST_RESOURCES); + } + break; + case StageT::TEST_RESOURCES: + if (TestResources()) { + SetStage(StageT::GENERATE); + } else { + SetStage(StageT::TEST_INFO_FILE); + } + break; + case StageT::TEST_INFO_FILE: + TestInfoFile(); + SetStage(StageT::GENERATE_WRAPPER); + break; + + // -- Generation + case StageT::GENERATE: + GenerateParentDir(); + SetStage(StageT::GENERATE_RCC); + break; + case StageT::GENERATE_RCC: + if (GenerateRcc()) { + SetStage(StageT::GENERATE_WRAPPER); + } + break; + case StageT::GENERATE_WRAPPER: + GenerateWrapper(); + SetStage(StageT::SETTINGS_WRITE); + break; + + // -- Finalize + case StageT::SETTINGS_WRITE: + SettingsFileWrite(); + SetStage(StageT::FINISH); + break; + case StageT::FINISH: + // Clear all libuv handles + UVRequest().reset(); + // Set highest END stage manually + Stage_ = StageT::END; + break; + case StageT::END: + break; + } +} + +void cmQtAutoGeneratorRcc::SetStage(StageT stage) +{ + if (Error_) { + stage = StageT::FINISH; + } + // Only allow to increase the stage + if (Stage_ < stage) { + Stage_ = stage; + UVRequest().send(); + } +} + +std::string cmQtAutoGeneratorRcc::MultiConfigOutput() const +{ + static std::string const suffix = "_CMAKE_"; + std::string res; + res += RccPathChecksum_; + res += '/'; + res += AppendFilenameSuffix(RccFileName_, suffix); + return res; +} + +void cmQtAutoGeneratorRcc::SettingsFileRead() +{ + // Compose current settings strings + { + cmCryptoHash crypt(cmCryptoHash::AlgoSHA256); + std::string const sep(" ~~~ "); + { + std::string str; + str += RccExecutable_; + str += sep; + str += cmJoin(RccListOptions_, ";"); + str += sep; + str += QrcFile_; + str += sep; + str += RccPathChecksum_; + str += sep; + str += RccFileName_; + str += sep; + str += cmJoin(Options_, ";"); + str += sep; + str += cmJoin(Inputs_, ";"); + str += sep; + SettingsString_ = crypt.HashString(str); + } + } + + // Read old settings + { + std::string content; + if (FileSys().FileRead(content, SettingsFile_)) { + SettingsChanged_ = (SettingsString_ != SettingsFind(content, "rcc")); + // 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 (SettingsChanged_) { + FileSys().FileRemove(SettingsFile_); + } + } else { + SettingsChanged_ = true; + } + } +} + +void cmQtAutoGeneratorRcc::SettingsFileWrite() +{ + // Only write if any setting changed + if (SettingsChanged_) { + if (Log().Verbose()) { + Log().Info(GeneratorT::RCC, + "Writing settings file " + Quoted(SettingsFile_)); + } + // Write settings file + std::string content = "rcc:"; + content += SettingsString_; + content += '\n'; + if (!FileSys().FileWrite(GeneratorT::RCC, SettingsFile_, content)) { + Log().ErrorFile(GeneratorT::RCC, SettingsFile_, + "Settings file writing failed"); + // Remove old settings file to trigger a full rebuild on the next run + FileSys().FileRemove(SettingsFile_); + Error_ = true; + } + } +} + +bool cmQtAutoGeneratorRcc::TestQrcRccFiles() +{ + // Do basic checks if rcc generation is required + + // Test if the rcc output file exists + if (!FileSys().FileExists(RccFileOutput_)) { + if (Log().Verbose()) { + std::string reason = "Generating "; + reason += Quoted(RccFileOutput_); + reason += " from its source file "; + reason += Quoted(QrcFile_); + reason += " because it doesn't exist"; + Log().Info(GeneratorT::RCC, reason); + } + Generate_ = true; + return Generate_; + } + + // Test if the settings changed + if (SettingsChanged_) { + if (Log().Verbose()) { + std::string reason = "Generating "; + reason += Quoted(RccFileOutput_); + reason += " from "; + reason += Quoted(QrcFile_); + reason += " because the RCC settings changed"; + Log().Info(GeneratorT::RCC, reason); + } + Generate_ = true; + return Generate_; + } + + // Test if the rcc output file is older than the .qrc file + { + bool isOlder = false; + { + std::string error; + isOlder = FileSys().FileIsOlderThan(RccFileOutput_, QrcFile_, &error); + if (!error.empty()) { + Log().ErrorFile(GeneratorT::RCC, QrcFile_, error); + Error_ = true; + } + } + if (isOlder) { + if (Log().Verbose()) { + std::string reason = "Generating "; + reason += Quoted(RccFileOutput_); + reason += " because it is older than "; + reason += Quoted(QrcFile_); + Log().Info(GeneratorT::RCC, reason); + } + Generate_ = true; + } + } + + return Generate_; +} + +bool cmQtAutoGeneratorRcc::TestResourcesRead() +{ + if (!Inputs_.empty()) { + // Inputs are known already + return true; + } + + if (!RccListOptions_.empty()) { + // Start a rcc list process and parse the output + if (Process_) { + // Process is running already + if (Process_->IsFinished()) { + // Process is finished + if (!ProcessResult_.error()) { + // Process success + std::string parseError; + if (!RccListParseOutput(ProcessResult_.StdOut, ProcessResult_.StdErr, + Inputs_, parseError)) { + Log().ErrorFile(GeneratorT::RCC, QrcFile_, parseError); + Error_ = true; + } + } else { + Log().ErrorFile(GeneratorT::RCC, QrcFile_, + ProcessResult_.ErrorMessage); + Error_ = true; + } + // Clean up + Process_.reset(); + ProcessResult_.reset(); + } else { + // Process is not finished, yet. + return false; + } + } else { + // Start a new process + // rcc prints relative entry paths when started in the directory of the + // qrc file with a pathless qrc file name argument. + // This is important because on Windows absolute paths returned by rcc + // might contain bad multibyte characters when the qrc file path + // contains non-ASCII pcharacters. + std::vector<std::string> cmd; + cmd.push_back(RccExecutable_); + cmd.insert(cmd.end(), RccListOptions_.begin(), RccListOptions_.end()); + cmd.push_back(QrcFileName_); + // We're done here if the process fails to start + return !StartProcess(QrcFileDir_, cmd, false); + } + } else { + // rcc does not support the --list command. + // Read the qrc file content and parse it. + std::string qrcContent; + if (FileSys().FileRead(GeneratorT::RCC, qrcContent, QrcFile_)) { + RccListParseContent(qrcContent, Inputs_); + } + } + + if (!Inputs_.empty()) { + // Convert relative paths to absolute paths + RccListConvertFullPath(QrcFileDir_, Inputs_); + } + + return true; +} + +bool cmQtAutoGeneratorRcc::TestResources() +{ + if (Inputs_.empty()) { + return true; + } + { + std::string error; + for (std::string const& resFile : Inputs_) { + // Check if the resource file exists + if (!FileSys().FileExists(resFile)) { + error = "Could not find the resource file\n "; + error += Quoted(resFile); + error += '\n'; + Log().ErrorFile(GeneratorT::RCC, QrcFile_, error); + Error_ = true; + break; + } + // Check if the resource file is newer than the build file + if (FileSys().FileIsOlderThan(RccFileOutput_, resFile, &error)) { + if (Log().Verbose()) { + std::string reason = "Generating "; + reason += Quoted(RccFileOutput_); + reason += " from "; + reason += Quoted(QrcFile_); + reason += " because it is older than "; + reason += Quoted(resFile); + Log().Info(GeneratorT::RCC, reason); + } + Generate_ = true; + break; + } + // Print error and break on demand + if (!error.empty()) { + Log().ErrorFile(GeneratorT::RCC, QrcFile_, error); + Error_ = true; + break; + } + } + } + + return Generate_; +} + +void cmQtAutoGeneratorRcc::TestInfoFile() +{ + // Test if the rcc output file is older than the info file + { + bool isOlder = false; + { + std::string error; + isOlder = FileSys().FileIsOlderThan(RccFileOutput_, InfoFile(), &error); + if (!error.empty()) { + Log().ErrorFile(GeneratorT::RCC, QrcFile_, error); + Error_ = true; + } + } + if (isOlder) { + if (Log().Verbose()) { + std::string reason = "Touching "; + reason += Quoted(RccFileOutput_); + reason += " because it is older than "; + reason += Quoted(InfoFile()); + Log().Info(GeneratorT::RCC, reason); + } + // Touch build file + FileSys().Touch(RccFileOutput_); + BuildFileChanged_ = true; + } + } +} + +void cmQtAutoGeneratorRcc::GenerateParentDir() +{ + // Make sure the parent directory exists + if (!FileSys().MakeParentDirectory(GeneratorT::RCC, RccFileOutput_)) { + Error_ = true; + } +} + +/** + * @return True when finished + */ +bool cmQtAutoGeneratorRcc::GenerateRcc() +{ + if (!Generate_) { + // Nothing to do + return true; + } + + if (Process_) { + // Process is running already + if (Process_->IsFinished()) { + // Process is finished + if (!ProcessResult_.error()) { + // Process success + BuildFileChanged_ = true; + } else { + // Process failed + { + std::string emsg = "The rcc process failed to compile\n "; + emsg += Quoted(QrcFile_); + emsg += "\ninto\n "; + emsg += Quoted(RccFileOutput_); + if (ProcessResult_.error()) { + emsg += "\n"; + emsg += ProcessResult_.ErrorMessage; + } + Log().ErrorCommand(GeneratorT::RCC, emsg, Process_->Setup().Command, + ProcessResult_.StdOut); + } + FileSys().FileRemove(RccFileOutput_); + Error_ = true; + } + // Clean up + Process_.reset(); + ProcessResult_.reset(); + } else { + // Process is not finished, yet. + return false; + } + } else { + // Start a rcc process + std::vector<std::string> cmd; + cmd.push_back(RccExecutable_); + cmd.insert(cmd.end(), Options_.begin(), Options_.end()); + cmd.push_back("-o"); + cmd.push_back(RccFileOutput_); + cmd.push_back(QrcFile_); + // We're done here if the process fails to start + return !StartProcess(AutogenBuildDir_, cmd, true); + } + + return true; +} + +void cmQtAutoGeneratorRcc::GenerateWrapper() +{ + // Generate a wrapper source file on demand + if (IsMultiConfig()) { + // Wrapper file content + std::string content; + content += "// This is an autogenerated configuration wrapper file.\n"; + content += "// Changes will be overwritten.\n"; + content += "#include <"; + content += MultiConfigOutput(); + content += ">\n"; + + // Write content to file + if (FileSys().FileDiffers(RccFilePublic_, content)) { + // Write new wrapper file + if (Log().Verbose()) { + Log().Info(GeneratorT::RCC, + "Generating RCC wrapper file " + RccFilePublic_); + } + if (!FileSys().FileWrite(GeneratorT::RCC, RccFilePublic_, content)) { + Log().ErrorFile(GeneratorT::RCC, RccFilePublic_, + "RCC wrapper file writing failed"); + Error_ = true; + } + } else if (BuildFileChanged_) { + // Just touch the wrapper file + if (Log().Verbose()) { + Log().Info(GeneratorT::RCC, + "Touching RCC wrapper file " + RccFilePublic_); + } + FileSys().Touch(RccFilePublic_); + } + } +} + +bool cmQtAutoGeneratorRcc::StartProcess( + std::string const& workingDirectory, std::vector<std::string> const& command, + bool mergedOutput) +{ + // Log command + if (Log().Verbose()) { + std::string msg = "Running command:\n"; + msg += QuotedCommand(command); + msg += '\n'; + Log().Info(GeneratorT::RCC, msg); + } + + // Create process handler + Process_ = cm::make_unique<ReadOnlyProcessT>(); + Process_->setup(&ProcessResult_, mergedOutput, command, workingDirectory); + // Start process + if (!Process_->start(UVLoop(), + std::bind(&cm::uv_async_ptr::send, &UVRequest()))) { + Log().ErrorFile(GeneratorT::RCC, QrcFile_, ProcessResult_.ErrorMessage); + Error_ = true; + // Clean up + Process_.reset(); + ProcessResult_.reset(); + return false; + } + return true; +} diff --git a/Source/cmQtAutoGeneratorRcc.h b/Source/cmQtAutoGeneratorRcc.h new file mode 100644 index 0000000..55e0998 --- /dev/null +++ b/Source/cmQtAutoGeneratorRcc.h @@ -0,0 +1,103 @@ +/* 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 "cmQtAutoGenerator.h" +#include "cm_uv.h" + +#include <string> +#include <vector> + +class cmMakefile; + +// @brief AUTORCC generator +class cmQtAutoGeneratorRcc : public cmQtAutoGenerator +{ + CM_DISABLE_COPY(cmQtAutoGeneratorRcc) +public: + cmQtAutoGeneratorRcc(); + ~cmQtAutoGeneratorRcc() override; + +private: + // -- Types + + /// @brief Processing stage + enum class StageT : unsigned char + { + SETTINGS_READ, + TEST_QRC_RCC_FILES, + TEST_RESOURCES_READ, + TEST_RESOURCES, + TEST_INFO_FILE, + GENERATE, + GENERATE_RCC, + GENERATE_WRAPPER, + SETTINGS_WRITE, + FINISH, + END + }; + + // -- Abstract processing interface + bool Init(cmMakefile* makefile) override; + bool Process() override; + // -- Process stage + static void UVPollStage(uv_async_t* handle); + void PollStage(); + void SetStage(StageT stage); + // -- Settings file + void SettingsFileRead(); + void SettingsFileWrite(); + // -- Tests + bool TestQrcRccFiles(); + bool TestResourcesRead(); + bool TestResources(); + void TestInfoFile(); + // -- Generation + void GenerateParentDir(); + bool GenerateRcc(); + void GenerateWrapper(); + + // -- Utility + bool IsMultiConfig() const { return MultiConfig_; } + std::string MultiConfigOutput() const; + bool StartProcess(std::string const& workingDirectory, + std::vector<std::string> const& command, + bool mergedOutput); + +private: + // -- Config settings + bool MultiConfig_; + // -- Directories + std::string AutogenBuildDir_; + std::string IncludeDir_; + // -- Qt environment + std::string RccExecutable_; + std::vector<std::string> RccListOptions_; + // -- Job + std::string QrcFile_; + std::string QrcFileName_; + std::string QrcFileDir_; + std::string RccPathChecksum_; + std::string RccFileName_; + std::string RccFileOutput_; + std::string RccFilePublic_; + std::vector<std::string> Options_; + std::vector<std::string> Inputs_; + // -- Subprocess + ProcessResultT ProcessResult_; + std::unique_ptr<ReadOnlyProcessT> Process_; + // -- Settings file + std::string SettingsFile_; + std::string SettingsString_; + bool SettingsChanged_; + // -- libuv loop + StageT Stage_; + bool Error_; + bool Generate_; + bool BuildFileChanged_; +}; + +#endif diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx deleted file mode 100644 index a9c9b9d..0000000 --- a/Source/cmQtAutoGenerators.cxx +++ /dev/null @@ -1,2335 +0,0 @@ -/* 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 "cmsys/FStream.hxx" -#include "cmsys/Terminal.h" -#include <algorithm> -#include <array> -#include <list> -#include <memory> -#include <sstream> -#include <string.h> -#include <utility> - -#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" - -#if defined(__APPLE__) -#include <unistd.h> -#endif - -// -- Static variables - -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)); - if (!res.empty()) { - res += '/'; - } - 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) -{ - return (std::find(list.begin(), list.end(), entry) != list.end()); -} - -// -- Class methods - -cmQtAutoGenerators::cmQtAutoGenerators() - : MultiConfig(cmQtAutoGen::WRAP) - , IncludeProjectDirsBefore(false) - , Verbose(cmSystemTools::HasEnv("VERBOSE")) - , ColorOutput(true) - , 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]+" - "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]"); - this->UicRegExpInclude.compile("[\n][ \t]*#[ \t]*include[ \t]+" - "[\"<](([^ \">]+/)?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); - // The OLD/WARN behavior for policy CMP0053 caused a speed regression. - // https://gitlab.kitware.com/cmake/cmake/issues/17570 - makefile->SetPolicyVersion("3.9"); - 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) -{ - // -- Meta - this->HeaderExtensions = makefile->GetCMakeInstance()->GetHeaderExtensions(); - - // Utility lambdas - auto InfoGet = [makefile](const char* key) { - return makefile->GetSafeDefinition(key); - }; - auto InfoGetBool = [makefile](const char* key) { - return makefile->IsOn(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 InfoGetLists = - [makefile](const char* key) -> std::vector<std::vector<std::string>> { - std::vector<std::vector<std::string>> lists; - { - std::string const value = makefile->GetSafeDefinition(key); - std::string::size_type pos = 0; - while (pos < value.size()) { - std::string::size_type next = value.find(cmQtAutoGen::listSep, pos); - std::string::size_type length = - (next != std::string::npos) ? next - pos : value.size() - pos; - // Remove enclosing braces - if (length >= 2) { - std::string::const_iterator itBeg = value.begin() + (pos + 1); - std::string::const_iterator itEnd = itBeg + (length - 2); - { - std::string subValue(itBeg, itEnd); - std::vector<std::string> list; - cmSystemTools::ExpandListArgument(subValue, list); - lists.push_back(std::move(list)); - } - } - pos += length; - pos += cmQtAutoGen::listSep.size(); - } - } - return lists; - }; - auto InfoGetConfig = [makefile, &config](const char* key) -> std::string { - const char* valueConf = nullptr; - { - std::string keyConf = key; - keyConf += '_'; - keyConf += config; - 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 - 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, - "File processing failed"); - return false; - } - - // -- Meta - this->MultiConfig = cmQtAutoGen::MultiConfigType(InfoGet("AM_MULTI_CONFIG")); - this->ConfigSuffix = InfoGetConfig("AM_CONFIG_SUFFIX"); - if (this->ConfigSuffix.empty()) { - this->ConfigSuffix = "_"; - this->ConfigSuffix += config; - } - - // - Files and directories - this->ProjectSourceDir = InfoGet("AM_CMAKE_SOURCE_DIR"); - this->ProjectBinaryDir = InfoGet("AM_CMAKE_BINARY_DIR"); - this->CurrentSourceDir = InfoGet("AM_CMAKE_CURRENT_SOURCE_DIR"); - this->CurrentBinaryDir = InfoGet("AM_CMAKE_CURRENT_BINARY_DIR"); - this->IncludeProjectDirsBefore = - InfoGetBool("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE"); - this->AutogenBuildDir = InfoGet("AM_BUILD_DIR"); - if (this->AutogenBuildDir.empty()) { - this->LogFileError(cmQtAutoGen::GEN, this->InfoFile, - "Autogen build directory missing"); - return false; - } - - // - Qt environment - this->QtMajorVersion = InfoGet("AM_QT_VERSION_MAJOR"); - this->QtMinorVersion = InfoGet("AM_QT_VERSION_MINOR"); - 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()) { - this->MocSkipList = InfoGetList("AM_MOC_SKIP"); - this->MocDefinitions = InfoGetConfigList("AM_MOC_DEFINITIONS"); -#ifdef _WIN32 - { - std::string const win32("WIN32"); - if (!ListContains(this->MocDefinitions, win32)) { - this->MocDefinitions.push_back(win32); - } - } -#endif - this->MocIncludePaths = InfoGetConfigList("AM_MOC_INCLUDES"); - this->MocOptions = InfoGetList("AM_MOC_OPTIONS"); - this->MocRelaxedMode = InfoGetBool("AM_MOC_RELAXED_MODE"); - { - std::vector<std::string> const MocMacroNames = - InfoGetList("AM_MOC_MACRO_NAMES"); - for (std::string const& item : MocMacroNames) { - this->MocMacroFilters.emplace_back( - item, ("[\n][ \t]*{?[ \t]*" + item).append("[^a-zA-Z0-9_]")); - } - } - { - std::vector<std::string> const mocDependFilters = - InfoGetList("AM_MOC_DEPEND_FILTERS"); - // Insert Q_PLUGIN_METADATA dependency filter - if (this->QtMajorVersion != "4") { - this->MocDependFilterPush("Q_PLUGIN_METADATA", - "[\n][ \t]*Q_PLUGIN_METADATA[ \t]*\\(" - "[^\\)]*FILE[ \t]*\"([^\"]+)\""); - } - // Insert user defined dependency filters - if ((mocDependFilters.size() % 2) == 0) { - for (std::vector<std::string>::const_iterator - dit = mocDependFilters.begin(), - ditEnd = mocDependFilters.end(); - dit != ditEnd; dit += 2) { - if (!this->MocDependFilterPush(*dit, *(dit + 1))) { - return false; - } - } - } else { - this->LogFileError( - cmQtAutoGen::MOC, this->InfoFile, - "AUTOMOC_DEPEND_FILTERS list size is not a multiple of 2"); - return false; - } - } - this->MocPredefsCmd = InfoGetList("AM_MOC_PREDEFS_CMD"); - } - - // - Uic - if (this->UicEnabled()) { - this->UicSkipList = InfoGetList("AM_UIC_SKIP"); - this->UicSearchPaths = InfoGetList("AM_UIC_SEARCH_PATHS"); - this->UicTargetOptions = InfoGetConfigList("AM_UIC_TARGET_OPTIONS"); - { - auto sources = InfoGetList("AM_UIC_OPTIONS_FILES"); - auto options = InfoGetLists("AM_UIC_OPTIONS_OPTIONS"); - // Compare list sizes - if (sources.size() != options.size()) { - std::ostringstream ost; - ost << "files/options lists sizes missmatch (" << sources.size() << "/" - << options.size() << ")"; - this->LogFileError(cmQtAutoGen::UIC, this->InfoFile, ost.str()); - return false; - } - auto fitEnd = sources.cend(); - auto fit = sources.begin(); - auto oit = options.begin(); - while (fit != fitEnd) { - this->UicOptions[*fit] = std::move(*oit); - ++fit; - ++oit; - } - } - } - - // - 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 - auto AddJob = [this](std::map<std::string, SourceJob>& jobs, - std::string&& sourceFile) { - const bool moc = !this->MocSkip(sourceFile); - const bool uic = !this->UicSkip(sourceFile); - if (moc || uic) { - SourceJob& job = jobs[std::move(sourceFile)]; - job.Moc = moc; - job.Uic = uic; - } - }; - - // Add header jobs - for (std::string& hdr : InfoGetList("AM_HEADERS")) { - AddJob(this->HeaderJobs, std::move(hdr)); - } - // Add source jobs - { - std::vector<std::string> sources = InfoGetList("AM_SOURCES"); - // Add header(s) for the source file - for (std::string const& src : sources) { - const bool srcMoc = !this->MocSkip(src); - const bool srcUic = !this->UicSkip(src); - if (!srcMoc && !srcUic) { - continue; - } - // Search for the default header file and a private header - std::array<std::string, 2> headerBases; - headerBases[0] = SubDirPrefix(src); - headerBases[0] += cmSystemTools::GetFilenameWithoutLastExtension(src); - headerBases[1] = headerBases[0]; - headerBases[1] += "_p"; - for (std::string const& headerBase : headerBases) { - std::string header; - if (this->FindHeader(header, headerBase)) { - const bool moc = srcMoc && !this->MocSkip(header); - const bool uic = srcUic && !this->UicSkip(header); - if (moc || uic) { - SourceJob& job = this->HeaderJobs[std::move(header)]; - job.Moc = moc; - job.Uic = uic; - } - } - } - } - // Add Source jobs - for (std::string& src : sources) { - AddJob(this->SourceJobs, std::move(src)); - } - } - } - - // Init derived information - // ------------------------ - - // Init file path checksum generator - this->FilePathChecksum.setupParentDirs( - this->CurrentSourceDir, this->CurrentBinaryDir, this->ProjectSourceDir, - this->ProjectBinaryDir); - - // include directory - this->AutogenIncludeDir = "include"; - if (this->MultiConfig != cmQtAutoGen::SINGLE) { - this->AutogenIncludeDir += this->ConfigSuffix; - } - this->AutogenIncludeDir += "/"; - - // Moc variables - if (this->MocEnabled()) { - // Mocs compilation file - this->MocCompFileRel = "mocs_compilation"; - if (this->MultiConfig == cmQtAutoGen::FULL) { - this->MocCompFileRel += this->ConfigSuffix; - } - this->MocCompFileRel += ".cpp"; - this->MocCompFileAbs = cmSystemTools::CollapseCombinedPath( - this->AutogenBuildDir, this->MocCompFileRel); - - // Moc predefs file - if (!this->MocPredefsCmd.empty()) { - this->MocPredefsFileRel = "moc_predefs"; - if (this->MultiConfig != cmQtAutoGen::SINGLE) { - this->MocPredefsFileRel += this->ConfigSuffix; - } - this->MocPredefsFileRel += ".h"; - this->MocPredefsFileAbs = cmSystemTools::CollapseCombinedPath( - this->AutogenBuildDir, this->MocPredefsFileRel); - } - - // Sort include directories on demand - if (this->IncludeProjectDirsBefore) { - // Move strings to temporary list - std::list<std::string> includes; - includes.insert(includes.end(), this->MocIncludePaths.begin(), - this->MocIncludePaths.end()); - this->MocIncludePaths.clear(); - this->MocIncludePaths.reserve(includes.size()); - // Append project directories only - { - std::array<std::string const*, 2> const movePaths = { - { &this->ProjectBinaryDir, &this->ProjectSourceDir } - }; - for (std::string const* ppath : movePaths) { - std::list<std::string>::iterator it = includes.begin(); - while (it != includes.end()) { - std::string const& path = *it; - if (cmSystemTools::StringStartsWith(path, ppath->c_str())) { - this->MocIncludePaths.push_back(path); - it = includes.erase(it); - } else { - ++it; - } - } - } - } - // Append remaining directories - this->MocIncludePaths.insert(this->MocIncludePaths.end(), - includes.begin(), includes.end()); - } - // Compose moc includes list - { - std::set<std::string> frameworkPaths; - for (std::string const& path : this->MocIncludePaths) { - this->MocIncludes.push_back("-I" + path); - // Extract framework path - if (cmHasLiteralSuffix(path, ".framework/Headers")) { - // Go up twice to get to the framework root - std::vector<std::string> pathComponents; - cmSystemTools::SplitPath(path, pathComponents); - std::string frameworkPath = cmSystemTools::JoinPath( - pathComponents.begin(), pathComponents.end() - 2); - frameworkPaths.insert(frameworkPath); - } - } - // Append framework includes - for (std::string const& path : frameworkPaths) { - this->MocIncludes.push_back("-F"); - this->MocIncludes.push_back(path); - } - } - // Setup single list with all options - { - // Add includes - this->MocAllOptions.insert(this->MocAllOptions.end(), - this->MocIncludes.begin(), - this->MocIncludes.end()); - // Add definitions - for (std::string const& def : this->MocDefinitions) { - this->MocAllOptions.push_back("-D" + def); - } - // Add options - this->MocAllOptions.insert(this->MocAllOptions.end(), - this->MocOptions.begin(), - this->MocOptions.end()); - } - } - - // - 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) -{ - // Compose current settings strings - { - cmCryptoHash crypt(cmCryptoHash::AlgoSHA256); - std::string const sep(" ~~~ "); - if (this->MocEnabled()) { - std::string str; - str += this->MocExecutable; - str += sep; - str += cmJoin(this->MocAllOptions, ";"); - str += sep; - str += this->IncludeProjectDirsBefore ? "TRUE" : "FALSE"; - str += sep; - str += cmJoin(this->MocPredefsCmd, ";"); - str += sep; - this->SettingsStringMoc = crypt.HashString(str); - } - if (this->UicEnabled()) { - std::string str; - str += this->UicExecutable; - str += sep; - str += cmJoin(this->UicTargetOptions, ";"); - for (const auto& item : this->UicOptions) { - str += sep; - str += item.first; - str += sep; - str += cmJoin(item.second, ";"); - } - 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 - if (makefile->ReadListFile(this->SettingsFile.c_str())) { - { - auto SMatch = [makefile](const char* key, std::string const& value) { - return (value == makefile->GetSafeDefinition(key)); - }; - if (!SMatch(SettingsKeyMoc, this->SettingsStringMoc)) { - this->MocSettingsChanged = true; - } - 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 - // 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->MocSettingsChanged = true; - this->UicSettingsChanged = true; - this->RccSettingsChanged = true; - } -} - -bool cmQtAutoGenerators::SettingsFileWrite() -{ - bool success = true; - // Only write if any setting changed - if (this->SettingsChanged()) { - if (this->Verbose) { - this->LogInfo(cmQtAutoGen::GEN, "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(SettingsKeyMoc, this->SettingsStringMoc); - SettingAppend(SettingsKeyUic, this->SettingsStringUic); - SettingAppend(SettingsKeyRcc, this->SettingsStringRcc); - } - // Write settings file - if (!this->FileWrite(cmQtAutoGen::GEN, this->SettingsFile, settings)) { - this->LogFileError(cmQtAutoGen::GEN, 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 cmQtAutoGenerators::Process() -{ - // 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 - // what file the moc is created from. Once a moc is included the same moc - // may not be included in the mocs_compilation.cpp file anymore. - // OTOH if there's a header containing Q_OBJECT where no corresponding - // moc file is included anywhere a moc_<filename>.cpp file is created and - // included in the mocs_compilation.cpp file. - - // Create AUTOGEN include directory - { - std::string const incDirAbs = cmSystemTools::CollapseCombinedPath( - this->AutogenBuildDir, this->AutogenIncludeDir); - if (!cmSystemTools::MakeDirectory(incDirAbs)) { - this->LogFileError(cmQtAutoGen::GEN, incDirAbs, - "Could not create directory"); - return false; - } - } - - // Parse source files - for (const auto& item : this->SourceJobs) { - if (!this->ParseSourceFile(item.first, item.second)) { - return false; - } - } - // Parse header files - for (const auto& item : this->HeaderJobs) { - if (!this->ParseHeaderFile(item.first, item.second)) { - return false; - } - } - // Read missing dependency information - if (!this->ParsePostprocess()) { - return false; - } - - // Generate files - if (!this->MocGenerateAll()) { - return false; - } - if (!this->UicGenerateAll()) { - return false; - } - if (!this->RccGenerateAll()) { - return false; - } - - return true; -} - -/** - * @return True on success - */ -bool cmQtAutoGenerators::ParseSourceFile(std::string const& absFilename, - const SourceJob& job) -{ - std::string contentText; - std::string error; - bool success = ReadFile(contentText, absFilename, &error); - if (success) { - if (!contentText.empty()) { - if (job.Moc) { - success = this->MocParseSourceContent(absFilename, contentText); - } - if (success && job.Uic) { - success = this->UicParseContent(absFilename, contentText); - } - } else { - this->LogFileWarning(cmQtAutoGen::GEN, absFilename, - "The source file is empty"); - } - } else { - this->LogFileError(cmQtAutoGen::GEN, absFilename, - "Could not read the source file: " + error); - } - return success; -} - -/** - * @return True on success - */ -bool cmQtAutoGenerators::ParseHeaderFile(std::string const& absFilename, - const SourceJob& job) -{ - std::string contentText; - std::string error; - bool success = ReadFile(contentText, absFilename, &error); - if (success) { - if (!contentText.empty()) { - if (job.Moc) { - this->MocParseHeaderContent(absFilename, contentText); - } - if (job.Uic) { - success = this->UicParseContent(absFilename, contentText); - } - } else { - this->LogFileWarning(cmQtAutoGen::GEN, absFilename, - "The header file is empty"); - } - } else { - this->LogFileError(cmQtAutoGen::GEN, absFilename, - "Could not read the header file: " + error); - } - return success; -} - -/** - * @return True on success - */ -bool cmQtAutoGenerators::ParsePostprocess() -{ - bool success = true; - // Read missin dependecies - for (auto& item : this->MocJobsIncluded) { - if (!item->DependsValid) { - std::string content; - std::string error; - if (ReadFile(content, item->SourceFile, &error)) { - this->MocFindDepends(item->SourceFile, content, item->Depends); - item->DependsValid = true; - } else { - std::string emsg = "Could not read file\n "; - emsg += item->SourceFile; - emsg += "\nrequired by moc include \""; - emsg += item->IncludeString; - emsg += "\".\n"; - emsg += error; - this->LogFileError(cmQtAutoGen::MOC, item->Includer, emsg); - success = false; - break; - } - } - } - return success; -} - -/** - * @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 -{ - if (this->MocEnabled()) { - // Test if the file name is on the skip list - if (!ListContains(this->MocSkipList, absFilename)) { - return false; - } - } - return true; -} - -/** - * @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) -{ - for (KeyRegExp& filter : this->MocMacroFilters) { - // Run a simple find string operation before the expensive - // regular expression check - if (contentText.find(filter.Key) != std::string::npos) { - if (filter.RegExp.find(contentText)) { - // Return macro name on demand - if (macroName != nullptr) { - *macroName = filter.Key; - } - return true; - } - } - } - return false; -} - -std::string cmQtAutoGenerators::MocStringMacros() const -{ - std::string res; - const auto itB = this->MocMacroFilters.cbegin(); - const auto itE = this->MocMacroFilters.cend(); - const auto itL = itE - 1; - auto itC = itB; - for (; itC != itE; ++itC) { - // Separator - if (itC != itB) { - if (itC != itL) { - res += ", "; - } else { - res += " or "; - } - } - // Key - res += itC->Key; - } - return res; -} - -std::string cmQtAutoGenerators::MocStringHeaders( - std::string const& fileBase) const -{ - std::string res = fileBase; - res += ".{"; - res += cmJoin(this->HeaderExtensions, ","); - res += "}"; - return res; -} - -std::string cmQtAutoGenerators::MocFindIncludedHeader( - std::string const& sourcePath, std::string const& includeBase) const -{ - std::string header; - // Search in vicinity of the source - if (!this->FindHeader(header, sourcePath + includeBase)) { - // Search in include directories - for (std::string const& path : this->MocIncludePaths) { - std::string fullPath = path; - fullPath.push_back('/'); - fullPath += includeBase; - if (this->FindHeader(header, fullPath)) { - break; - } - } - } - // Sanitize - if (!header.empty()) { - header = cmSystemTools::GetRealPath(header); - } - return header; -} - -bool cmQtAutoGenerators::MocFindIncludedFile( - std::string& absFile, std::string const& sourcePath, - std::string const& includeString) const -{ - bool success = false; - // Search in vicinity of the source - { - std::string testPath = sourcePath; - testPath += includeString; - if (cmSystemTools::FileExists(testPath.c_str())) { - absFile = cmSystemTools::GetRealPath(testPath); - success = true; - } - } - // Search in include directories - if (!success) { - for (std::string const& path : this->MocIncludePaths) { - std::string fullPath = path; - fullPath.push_back('/'); - fullPath += includeString; - if (cmSystemTools::FileExists(fullPath.c_str())) { - absFile = cmSystemTools::GetRealPath(fullPath); - success = true; - break; - } - } - } - return success; -} - -bool cmQtAutoGenerators::MocDependFilterPush(std::string const& key, - std::string const& regExp) -{ - std::string error; - if (!key.empty()) { - if (!regExp.empty()) { - KeyRegExp filter; - filter.Key = key; - if (filter.RegExp.compile(regExp)) { - this->MocDependFilters.push_back(std::move(filter)); - } else { - error = "Regular expression compiling failed"; - } - } else { - error = "Regular expression is empty"; - } - } else { - error = "Key is empty"; - } - if (!error.empty()) { - std::string emsg = "AUTOMOC_DEPEND_FILTERS: "; - emsg += error; - emsg += "\n"; - emsg += " Key: "; - emsg += cmQtAutoGen::Quoted(key); - emsg += "\n"; - emsg += " RegExp: "; - emsg += cmQtAutoGen::Quoted(regExp); - emsg += "\n"; - this->LogError(cmQtAutoGen::MOC, emsg); - return false; - } - return true; -} - -void cmQtAutoGenerators::MocFindDepends(std::string const& absFilename, - std::string const& contentText, - std::set<std::string>& depends) -{ - if (this->MocDependFilters.empty() && contentText.empty()) { - return; - } - - std::vector<std::string> matches; - for (KeyRegExp& filter : this->MocDependFilters) { - // Run a simple find string check - if (contentText.find(filter.Key) != std::string::npos) { - // Run the expensive regular expression check loop - const char* contentChars = contentText.c_str(); - while (filter.RegExp.find(contentChars)) { - std::string match = filter.RegExp.match(1); - if (!match.empty()) { - matches.emplace_back(std::move(match)); - } - contentChars += filter.RegExp.end(); - } - } - } - - if (!matches.empty()) { - std::string const sourcePath = SubDirPrefix(absFilename); - for (std::string const& match : matches) { - // Find the dependency file - std::string incFile; - if (this->MocFindIncludedFile(incFile, sourcePath, match)) { - depends.insert(incFile); - if (this->Verbose) { - this->LogInfo(cmQtAutoGen::MOC, "Found dependency:\n " + - cmQtAutoGen::Quoted(absFilename) + "\n " + - cmQtAutoGen::Quoted(incFile)); - } - } else { - this->LogFileWarning(cmQtAutoGen::MOC, absFilename, - "Could not find dependency file " + - cmQtAutoGen::Quoted(match)); - } - } - } -} - -/** - * @return True on success - */ -bool cmQtAutoGenerators::MocParseSourceContent(std::string const& absFilename, - std::string const& contentText) -{ - if (this->Verbose) { - this->LogInfo(cmQtAutoGen::MOC, "Checking: " + absFilename); - } - - auto AddJob = [this, &absFilename](std::string const& sourceFile, - std::string const& includeString, - std::string const* content) { - auto job = cm::make_unique<MocJobIncluded>(); - job->SourceFile = sourceFile; - job->BuildFileRel = this->AutogenIncludeDir; - job->BuildFileRel += includeString; - job->Includer = absFilename; - job->IncludeString = includeString; - job->DependsValid = (content != nullptr); - if (job->DependsValid) { - this->MocFindDepends(sourceFile, *content, job->Depends); - } - this->MocJobsIncluded.push_back(std::move(job)); - }; - - struct MocInc - { - std::string Inc; // full include string - std::string Dir; // include string directory - std::string Base; // include string file base - }; - - // Extract moc includes from file - std::vector<MocInc> mocIncsUsc; - std::vector<MocInc> mocIncsDot; - { - const char* contentChars = contentText.c_str(); - if (strstr(contentChars, "moc") != nullptr) { - while (this->MocRegExpInclude.find(contentChars)) { - std::string incString = this->MocRegExpInclude.match(1); - std::string incDir(SubDirPrefix(incString)); - std::string incBase = - cmSystemTools::GetFilenameWithoutLastExtension(incString); - if (cmHasLiteralPrefix(incBase, "moc_")) { - // moc_<BASE>.cxx - // Remove the moc_ part from the base name - mocIncsUsc.push_back(MocInc{ std::move(incString), std::move(incDir), - incBase.substr(4) }); - } else { - // <BASE>.moc - mocIncsDot.push_back(MocInc{ std::move(incString), std::move(incDir), - std::move(incBase) }); - } - // Forward content pointer - contentChars += this->MocRegExpInclude.end(); - } - } - } - - std::string selfMacroName; - const bool selfRequiresMoc = this->MocRequired(contentText, &selfMacroName); - - // Check if there is anything to do - if (!selfRequiresMoc && mocIncsUsc.empty() && mocIncsDot.empty()) { - return true; - } - - // Scan file variables - std::string const scanFileDir = SubDirPrefix(absFilename); - std::string const scanFileBase = - cmSystemTools::GetFilenameWithoutLastExtension(absFilename); - // Relaxed mode variables - bool ownDotMocIncluded = false; - std::string ownMocUscInclude; - std::string ownMocUscHeader; - - // Process moc_<BASE>.cxx includes - for (const MocInc& mocInc : mocIncsUsc) { - std::string const header = - this->MocFindIncludedHeader(scanFileDir, mocInc.Dir + mocInc.Base); - if (!header.empty()) { - // Check if header is skipped - if (this->MocSkip(header)) { - continue; - } - // Register moc job - AddJob(header, mocInc.Inc, nullptr); - // Store meta information for relaxed mode - if (this->MocRelaxedMode && (mocInc.Base == scanFileBase)) { - ownMocUscInclude = mocInc.Inc; - ownMocUscHeader = header; - } - } else { - std::string emsg = "The file includes the moc file "; - emsg += cmQtAutoGen::Quoted(mocInc.Inc); - emsg += ", but could not find the header "; - emsg += cmQtAutoGen::Quoted(this->MocStringHeaders(mocInc.Base)); - this->LogFileError(cmQtAutoGen::MOC, absFilename, emsg); - return false; - } - } - - // Process <BASE>.moc includes - for (const MocInc& mocInc : mocIncsDot) { - const bool ownMoc = (mocInc.Base == scanFileBase); - if (this->MocRelaxedMode) { - // Relaxed mode - if (selfRequiresMoc && ownMoc) { - // Add self - AddJob(absFilename, mocInc.Inc, &contentText); - ownDotMocIncluded = true; - } else { - // In relaxed mode try to find a header instead but issue a warning. - // This is for KDE4 compatibility - std::string const header = - this->MocFindIncludedHeader(scanFileDir, mocInc.Dir + mocInc.Base); - if (!header.empty()) { - // Check if header is skipped - if (this->MocSkip(header)) { - continue; - } - // Register moc job - AddJob(header, mocInc.Inc, nullptr); - if (!selfRequiresMoc) { - if (ownMoc) { - std::string emsg = "The file includes the moc file "; - emsg += cmQtAutoGen::Quoted(mocInc.Inc); - emsg += ", but does not contain a "; - emsg += this->MocStringMacros(); - emsg += " macro.\nRunning moc on\n "; - emsg += cmQtAutoGen::Quoted(header); - emsg += "!\nBetter include "; - emsg += cmQtAutoGen::Quoted("moc_" + mocInc.Base + ".cpp"); - emsg += " for a compatibility with strict mode.\n" - "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n"; - this->LogFileWarning(cmQtAutoGen::MOC, absFilename, emsg); - } else { - std::string emsg = "The file includes the moc file "; - emsg += cmQtAutoGen::Quoted(mocInc.Inc); - emsg += " instead of "; - emsg += cmQtAutoGen::Quoted("moc_" + mocInc.Base + ".cpp"); - emsg += ".\nRunning moc on\n "; - emsg += cmQtAutoGen::Quoted(header); - emsg += "!\nBetter include "; - emsg += cmQtAutoGen::Quoted("moc_" + mocInc.Base + ".cpp"); - emsg += " for compatibility with strict mode.\n" - "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n"; - this->LogFileWarning(cmQtAutoGen::MOC, absFilename, emsg); - } - } - } else { - std::string emsg = "The file includes the moc file "; - emsg += cmQtAutoGen::Quoted(mocInc.Inc); - emsg += ", which seems to be the moc file from a different " - "source file. CMake also could not find a matching " - "header."; - this->LogFileError(cmQtAutoGen::MOC, absFilename, emsg); - return false; - } - } - } else { - // Strict mode - if (ownMoc) { - // Include self - AddJob(absFilename, mocInc.Inc, &contentText); - ownDotMocIncluded = true; - // Accept but issue a warning if moc isn't required - if (!selfRequiresMoc) { - std::string emsg = "The file includes the moc file "; - emsg += cmQtAutoGen::Quoted(mocInc.Inc); - emsg += ", but does not contain a "; - emsg += this->MocStringMacros(); - emsg += " macro."; - this->LogFileWarning(cmQtAutoGen::MOC, absFilename, emsg); - } - } else { - // Don't allow <BASE>.moc include other than self in strict mode - std::string emsg = "The file includes the moc file "; - emsg += cmQtAutoGen::Quoted(mocInc.Inc); - emsg += ", which seems to be the moc file from a different " - "source file.\nThis is not supported. Include "; - emsg += cmQtAutoGen::Quoted(scanFileBase + ".moc"); - emsg += " to run moc on this source file."; - this->LogFileError(cmQtAutoGen::MOC, absFilename, emsg); - return false; - } - } - } - - if (selfRequiresMoc && !ownDotMocIncluded) { - // In this case, check whether the scanned file itself contains a Q_OBJECT. - // If this is the case, the moc_foo.cpp should probably be generated from - // foo.cpp instead of foo.h, because otherwise it won't build. - // But warn, since this is not how it is supposed to be used. - if (this->MocRelaxedMode && !ownMocUscInclude.empty()) { - // This is for KDE4 compatibility: - std::string emsg = "The file contains a "; - emsg += selfMacroName; - emsg += " macro, but does not include "; - emsg += cmQtAutoGen::Quoted(scanFileBase + ".moc"); - emsg += ". Instead it includes "; - emsg += cmQtAutoGen::Quoted(ownMocUscInclude); - emsg += ".\nRunning moc on\n "; - emsg += cmQtAutoGen::Quoted(absFilename); - emsg += "!\nBetter include "; - emsg += cmQtAutoGen::Quoted(scanFileBase + ".moc"); - emsg += " for compatibility with strict mode.\n" - "(CMAKE_AUTOMOC_RELAXED_MODE warning)"; - this->LogFileWarning(cmQtAutoGen::MOC, absFilename, emsg); - - // Remove own header job - { - auto itC = this->MocJobsIncluded.begin(); - auto itE = this->MocJobsIncluded.end(); - for (; itC != itE; ++itC) { - if ((*itC)->SourceFile == ownMocUscHeader) { - if ((*itC)->IncludeString == ownMocUscInclude) { - this->MocJobsIncluded.erase(itC); - break; - } - } - } - } - // Add own source job - AddJob(absFilename, ownMocUscInclude, &contentText); - } else { - // Otherwise always error out since it will not compile: - std::string emsg = "The file contains a "; - emsg += selfMacroName; - emsg += " macro, but does not include "; - emsg += cmQtAutoGen::Quoted(scanFileBase + ".moc"); - emsg += "!\nConsider to\n - add #include \""; - emsg += scanFileBase; - emsg += ".moc\"\n - enable SKIP_AUTOMOC for this file"; - this->LogFileError(cmQtAutoGen::MOC, absFilename, emsg); - return false; - } - } - return true; -} - -void cmQtAutoGenerators::MocParseHeaderContent(std::string const& absFilename, - std::string const& contentText) -{ - if (this->Verbose) { - this->LogInfo(cmQtAutoGen::MOC, "Checking: " + absFilename); - } - - auto const fit = - std::find_if(this->MocJobsIncluded.cbegin(), this->MocJobsIncluded.cend(), - [&absFilename](std::unique_ptr<MocJobIncluded> const& job) { - return job->SourceFile == absFilename; - }); - if (fit == this->MocJobsIncluded.cend()) { - if (this->MocRequired(contentText)) { - auto job = cm::make_unique<MocJobAuto>(); - job->SourceFile = absFilename; - { - std::string& bld = job->BuildFileRel; - bld = this->FilePathChecksum.getPart(absFilename); - bld += '/'; - bld += "moc_"; - bld += cmSystemTools::GetFilenameWithoutLastExtension(absFilename); - if (this->MultiConfig != cmQtAutoGen::SINGLE) { - bld += this->ConfigSuffix; - } - bld += ".cpp"; - } - this->MocFindDepends(absFilename, contentText, job->Depends); - this->MocJobsAuto.push_back(std::move(job)); - } - } -} - -bool cmQtAutoGenerators::MocGenerateAll() -{ - if (!this->MocEnabled()) { - return true; - } - - // Look for name collisions in included moc files - { - bool collision = false; - std::map<std::string, std::vector<MocJobIncluded const*>> collisions; - for (auto const& job : this->MocJobsIncluded) { - auto& list = collisions[job->IncludeString]; - if (!list.empty()) { - collision = true; - } - list.push_back(job.get()); - } - if (collision) { - std::string emsg = - "Included moc files with the same name will be " - "generated from different sources.\n" - "Consider to\n" - " - not include the \"moc_<NAME>.cpp\" file\n" - " - add a directory prefix to a \"<NAME>.moc\" include " - "(e.g \"sub/<NAME>.moc\")\n" - " - rename the source file(s)\n" - "Include conflicts\n" - "-----------------\n"; - const auto& colls = collisions; - for (auto const& coll : colls) { - if (coll.second.size() > 1) { - emsg += cmQtAutoGen::Quoted(coll.first); - emsg += " included in\n"; - for (const MocJobIncluded* job : coll.second) { - emsg += " - "; - emsg += cmQtAutoGen::Quoted(job->Includer); - emsg += "\n"; - } - emsg += "would be generated from\n"; - for (const MocJobIncluded* job : coll.second) { - emsg += " - "; - emsg += cmQtAutoGen::Quoted(job->SourceFile); - emsg += "\n"; - } - } - } - this->LogError(cmQtAutoGen::MOC, emsg); - return false; - } - } - - // (Re)generate moc_predefs.h on demand - if (!this->MocPredefsCmd.empty()) { - if (this->MocSettingsChanged || - !cmSystemTools::FileExists(this->MocPredefsFileAbs)) { - if (this->Verbose) { - this->LogBold("Generating MOC predefs " + this->MocPredefsFileRel); - } - - std::string output; - { - // Compose command - std::vector<std::string> cmd = this->MocPredefsCmd; - // Add includes - cmd.insert(cmd.end(), this->MocIncludes.begin(), - this->MocIncludes.end()); - // Add definitions - for (std::string const& def : this->MocDefinitions) { - cmd.push_back("-D" + def); - } - // Execute command - if (!this->RunCommand(cmd, output)) { - this->LogCommandError(cmQtAutoGen::MOC, - "moc_predefs generation failed", cmd, output); - return false; - } - } - - // (Re)write predefs file only on demand - if (this->FileDiffers(this->MocPredefsFileAbs, output)) { - if (this->FileWrite(cmQtAutoGen::MOC, this->MocPredefsFileAbs, - output)) { - this->MocPredefsChanged = true; - } else { - this->LogFileError(cmQtAutoGen::MOC, this->MocPredefsFileAbs, - "moc_predefs file writing failed"); - return false; - } - } else { - // Touch to update the time stamp - if (this->Verbose) { - this->LogInfo(cmQtAutoGen::MOC, - "Touching moc_predefs " + this->MocPredefsFileRel); - } - cmSystemTools::Touch(this->MocPredefsFileAbs, false); - } - } - - // Add moc_predefs.h to moc file dependecies - for (auto const& item : this->MocJobsIncluded) { - item->Depends.insert(this->MocPredefsFileAbs); - } - for (auto const& item : this->MocJobsAuto) { - item->Depends.insert(this->MocPredefsFileAbs); - } - } - - // Generate moc files that are included by source files. - for (auto const& item : this->MocJobsIncluded) { - if (!this->MocGenerateFile(*item)) { - return false; - } - } - // Generate moc files that are _not_ included by source files. - bool autoNameGenerated = false; - for (auto const& item : this->MocJobsAuto) { - if (!this->MocGenerateFile(*item, &autoNameGenerated)) { - return false; - } - } - - // Compose mocs compilation file content - { - std::string mocs = - "// This file is autogenerated. Changes will be overwritten.\n"; - if (this->MocJobsAuto.empty()) { - // Placeholder content - mocs += - "// No files found that require moc or the moc files are included\n"; - mocs += "enum some_compilers { need_more_than_nothing };\n"; - } else { - // Valid content - for (const auto& item : this->MocJobsAuto) { - mocs += "#include \""; - mocs += item->BuildFileRel; - mocs += "\"\n"; - } - } - - if (this->FileDiffers(this->MocCompFileAbs, mocs)) { - // Actually write mocs compilation file - if (this->Verbose) { - this->LogBold("Generating MOC compilation " + this->MocCompFileRel); - } - if (!this->FileWrite(cmQtAutoGen::MOC, this->MocCompFileAbs, mocs)) { - this->LogFileError(cmQtAutoGen::MOC, this->MocCompFileAbs, - "mocs compilation file writing failed"); - return false; - } - } else if (autoNameGenerated) { - // Only touch mocs compilation file - if (this->Verbose) { - this->LogInfo(cmQtAutoGen::MOC, - "Touching mocs compilation " + this->MocCompFileRel); - } - cmSystemTools::Touch(this->MocCompFileAbs, false); - } - } - - return true; -} - -/** - * @return True on success - */ -bool cmQtAutoGenerators::MocGenerateFile(const MocJobAuto& mocJob, - bool* generated) -{ - bool success = true; - - std::string const mocFileAbs = cmSystemTools::CollapseCombinedPath( - this->AutogenBuildDir, mocJob.BuildFileRel); - - bool generate = false; - std::string generateReason; - if (!generate && !cmSystemTools::FileExists(mocFileAbs.c_str())) { - if (this->Verbose) { - generateReason = "Generating "; - generateReason += cmQtAutoGen::Quoted(mocFileAbs); - generateReason += " from its source file "; - generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile); - generateReason += " because it doesn't exist"; - } - generate = true; - } - if (!generate && this->MocSettingsChanged) { - if (this->Verbose) { - generateReason = "Generating "; - generateReason += cmQtAutoGen::Quoted(mocFileAbs); - generateReason += " from "; - generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile); - generateReason += " because the MOC settings changed"; - } - generate = true; - } - if (!generate && this->MocPredefsChanged) { - if (this->Verbose) { - generateReason = "Generating "; - generateReason += cmQtAutoGen::Quoted(mocFileAbs); - generateReason += " from "; - generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile); - generateReason += " because moc_predefs.h changed"; - } - generate = true; - } - if (!generate) { - std::string error; - if (FileIsOlderThan(mocFileAbs, mocJob.SourceFile, &error)) { - if (this->Verbose) { - generateReason = "Generating "; - generateReason += cmQtAutoGen::Quoted(mocFileAbs); - generateReason += " because it's older than its source file "; - generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile); - } - generate = true; - } else { - if (!error.empty()) { - this->LogError(cmQtAutoGen::MOC, error); - success = false; - } - } - } - if (success && !generate) { - // Test if a dependency file is newer - std::string error; - for (std::string const& depFile : mocJob.Depends) { - if (FileIsOlderThan(mocFileAbs, depFile, &error)) { - if (this->Verbose) { - generateReason = "Generating "; - generateReason += cmQtAutoGen::Quoted(mocFileAbs); - generateReason += " from "; - generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile); - generateReason += " because it is older than "; - generateReason += cmQtAutoGen::Quoted(depFile); - } - generate = true; - break; - } - if (!error.empty()) { - this->LogError(cmQtAutoGen::MOC, error); - success = false; - break; - } - } - } - - if (generate) { - // Log - if (this->Verbose) { - this->LogBold("Generating MOC source " + mocJob.BuildFileRel); - this->LogInfo(cmQtAutoGen::MOC, generateReason); - } - - // Make sure the parent directory exists - if (this->MakeParentDirectory(cmQtAutoGen::MOC, mocFileAbs)) { - // Compose moc command - std::vector<std::string> cmd; - cmd.push_back(this->MocExecutable); - // Add options - cmd.insert(cmd.end(), this->MocAllOptions.begin(), - this->MocAllOptions.end()); - // Add predefs include - if (!this->MocPredefsFileAbs.empty()) { - cmd.push_back("--include"); - cmd.push_back(this->MocPredefsFileAbs); - } - cmd.push_back("-o"); - cmd.push_back(mocFileAbs); - cmd.push_back(mocJob.SourceFile); - - // Execute moc command - std::string output; - if (this->RunCommand(cmd, output)) { - // Success - if (generated != nullptr) { - *generated = true; - } - } else { - // Moc command failed - { - std::string emsg = "moc failed for\n "; - emsg += cmQtAutoGen::Quoted(mocJob.SourceFile); - this->LogCommandError(cmQtAutoGen::MOC, emsg, cmd, output); - } - cmSystemTools::RemoveFile(mocFileAbs); - success = false; - } - } else { - // Parent directory creation failed - success = false; - } - } - return success; -} - -/** - * @brief Tests if the file name is in the skip list - */ -bool cmQtAutoGenerators::UicSkip(std::string const& absFilename) const -{ - if (this->UicEnabled()) { - // Test if the file name is on the skip list - if (!ListContains(this->UicSkipList, absFilename)) { - return false; - } - } - return true; -} - -bool cmQtAutoGenerators::UicParseContent(std::string const& absFilename, - std::string const& contentText) -{ - if (this->Verbose) { - this->LogInfo(cmQtAutoGen::UIC, "Checking: " + absFilename); - } - - std::vector<std::string> includes; - // Extracte includes - { - const char* contentChars = contentText.c_str(); - if (strstr(contentChars, "ui_") != nullptr) { - while (this->UicRegExpInclude.find(contentChars)) { - includes.push_back(this->UicRegExpInclude.match(1)); - contentChars += this->UicRegExpInclude.end(); - } - } - } - - for (std::string const& includeString : includes) { - std::string uiInputFile; - if (!UicFindIncludedFile(uiInputFile, absFilename, includeString)) { - return false; - } - // Check if this file should be skipped - if (this->UicSkip(uiInputFile)) { - continue; - } - // Check if the job already exists - bool jobExists = false; - for (const auto& job : this->UicJobs) { - if ((job->SourceFile == uiInputFile) && - (job->IncludeString == includeString)) { - jobExists = true; - break; - } - } - if (!jobExists) { - auto job = cm::make_unique<UicJob>(); - job->SourceFile = uiInputFile; - job->BuildFileRel = this->AutogenIncludeDir; - job->BuildFileRel += includeString; - job->Includer = absFilename; - job->IncludeString = includeString; - this->UicJobs.push_back(std::move(job)); - } - } - - return true; -} - -bool cmQtAutoGenerators::UicFindIncludedFile(std::string& absFile, - std::string const& sourceFile, - std::string const& includeString) -{ - bool success = false; - std::string searchFile = - cmSystemTools::GetFilenameWithoutLastExtension(includeString).substr(3); - searchFile += ".ui"; - // Collect search paths list - std::vector<std::string> testFiles; - { - std::string const searchPath = SubDirPrefix(includeString); - - std::string searchFileFull; - if (!searchPath.empty()) { - searchFileFull = searchPath; - searchFileFull += searchFile; - } - // Vicinity of the source - { - std::string const sourcePath = SubDirPrefix(sourceFile); - testFiles.push_back(sourcePath + searchFile); - if (!searchPath.empty()) { - testFiles.push_back(sourcePath + searchFileFull); - } - } - // AUTOUIC search paths - if (!this->UicSearchPaths.empty()) { - for (std::string const& sPath : this->UicSearchPaths) { - testFiles.push_back((sPath + "/").append(searchFile)); - } - if (!searchPath.empty()) { - for (std::string const& sPath : this->UicSearchPaths) { - testFiles.push_back((sPath + "/").append(searchFileFull)); - } - } - } - } - - // Search for the .ui file! - for (std::string const& testFile : testFiles) { - if (cmSystemTools::FileExists(testFile.c_str())) { - absFile = cmSystemTools::GetRealPath(testFile); - success = true; - break; - } - } - - // Log error - if (!success) { - std::string emsg = "Could not find "; - emsg += cmQtAutoGen::Quoted(searchFile); - emsg += " in\n"; - for (std::string const& testFile : testFiles) { - emsg += " "; - emsg += cmQtAutoGen::Quoted(testFile); - emsg += "\n"; - } - this->LogFileError(cmQtAutoGen::UIC, sourceFile, emsg); - } - - return success; -} - -bool cmQtAutoGenerators::UicGenerateAll() -{ - if (!this->UicEnabled()) { - return true; - } - - // Look for name collisions in included uic files - { - bool collision = false; - std::map<std::string, std::vector<UicJob const*>> collisions; - for (auto const& job : this->UicJobs) { - auto& list = collisions[job->IncludeString]; - if (!list.empty()) { - collision = true; - } - list.push_back(job.get()); - } - if (collision) { - std::string emsg = - "Included uic files with the same name will be " - "generated from different sources.\n" - "Consider to\n" - " - add a directory prefix to a \"ui_<NAME>.h\" include " - "(e.g \"sub/ui_<NAME>.h\")\n" - " - rename the <NAME>.ui file(s) and adjust the \"ui_<NAME>.h\" " - "include(s)\n" - "Include conflicts\n" - "-----------------\n"; - const auto& colls = collisions; - for (auto const& coll : colls) { - if (coll.second.size() > 1) { - emsg += cmQtAutoGen::Quoted(coll.first); - emsg += " included in\n"; - for (const UicJob* job : coll.second) { - emsg += " - "; - emsg += cmQtAutoGen::Quoted(job->Includer); - emsg += "\n"; - } - emsg += "would be generated from\n"; - for (const UicJob* job : coll.second) { - emsg += " - "; - emsg += cmQtAutoGen::Quoted(job->SourceFile); - emsg += "\n"; - } - } - } - this->LogError(cmQtAutoGen::UIC, emsg); - return false; - } - } - - // Generate ui header files - for (const auto& item : this->UicJobs) { - if (!this->UicGenerateFile(*item)) { - return false; - } - } - - return true; -} - -/** - * @return True on success - */ -bool cmQtAutoGenerators::UicGenerateFile(const UicJob& uicJob) -{ - bool success = true; - - std::string const uicFileAbs = cmSystemTools::CollapseCombinedPath( - this->AutogenBuildDir, uicJob.BuildFileRel); - - bool generate = false; - std::string generateReason; - if (!generate && !cmSystemTools::FileExists(uicFileAbs.c_str())) { - if (this->Verbose) { - generateReason = "Generating "; - generateReason += cmQtAutoGen::Quoted(uicFileAbs); - generateReason += " from its source file "; - generateReason += cmQtAutoGen::Quoted(uicJob.SourceFile); - generateReason += " because it doesn't exist"; - } - generate = true; - } - if (!generate && this->UicSettingsChanged) { - if (this->Verbose) { - generateReason = "Generating "; - generateReason += cmQtAutoGen::Quoted(uicFileAbs); - generateReason += " from "; - generateReason += cmQtAutoGen::Quoted(uicJob.SourceFile); - generateReason += " because the UIC settings changed"; - } - generate = true; - } - if (!generate) { - std::string error; - if (FileIsOlderThan(uicFileAbs, uicJob.SourceFile, &error)) { - if (this->Verbose) { - generateReason = "Generating "; - generateReason += cmQtAutoGen::Quoted(uicFileAbs); - generateReason += " because it's older than its source file "; - generateReason += cmQtAutoGen::Quoted(uicJob.SourceFile); - } - generate = true; - } else { - if (!error.empty()) { - this->LogError(cmQtAutoGen::UIC, error); - success = false; - } - } - } - if (generate) { - // Log - if (this->Verbose) { - this->LogBold("Generating UIC header " + uicJob.BuildFileRel); - this->LogInfo(cmQtAutoGen::UIC, generateReason); - } - - // Make sure the parent directory exists - if (this->MakeParentDirectory(cmQtAutoGen::UIC, uicFileAbs)) { - // Compose uic command - std::vector<std::string> cmd; - cmd.push_back(this->UicExecutable); - { - std::vector<std::string> allOpts = this->UicTargetOptions; - auto optionIt = this->UicOptions.find(uicJob.SourceFile); - if (optionIt != this->UicOptions.end()) { - cmQtAutoGen::UicMergeOptions(allOpts, optionIt->second, - (this->QtMajorVersion == "5")); - } - cmd.insert(cmd.end(), allOpts.begin(), allOpts.end()); - } - cmd.push_back("-o"); - cmd.push_back(uicFileAbs); - cmd.push_back(uicJob.SourceFile); - - std::string output; - if (this->RunCommand(cmd, output)) { - // Success - } else { - // Command failed - { - std::string emsg = "uic failed for\n "; - emsg += cmQtAutoGen::Quoted(uicJob.SourceFile); - emsg += "\nincluded by\n "; - emsg += cmQtAutoGen::Quoted(uicJob.Includer); - this->LogCommandError(cmQtAutoGen::UIC, emsg, cmd, output); - } - cmSystemTools::RemoveFile(uicFileAbs); - success = false; - } - } else { - // Parent directory creation failed - success = false; - } - } - 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 -{ - for (std::string const& ext : this->HeaderExtensions) { - std::string testFilePath(testBasePath); - testFilePath.push_back('.'); - testFilePath += ext; - if (cmSystemTools::FileExists(testFilePath.c_str())) { - header = testFilePath; - return true; - } - } - return false; -} diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h deleted file mode 100644 index a7bb538..0000000 --- a/Source/cmQtAutoGenerators.h +++ /dev/null @@ -1,248 +0,0 @@ -/* 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 - -#include "cmConfigure.h" // IWYU pragma: keep - -#include "cmFilePathChecksum.h" -#include "cmQtAutoGen.h" -#include "cmsys/RegularExpression.hxx" - -#include <map> -#include <memory> // IWYU pragma: keep -#include <set> -#include <string> -#include <vector> - -class cmMakefile; - -class cmQtAutoGenerators -{ - CM_DISABLE_COPY(cmQtAutoGenerators) -public: - cmQtAutoGenerators(); - bool Run(std::string const& targetDirectory, std::string const& config); - -private: - // -- Types - - /// @brief Search key plus regular expression pair - struct KeyRegExp - { - KeyRegExp() = default; - - KeyRegExp(const char* key, const char* regExp) - : Key(key) - , RegExp(regExp) - { - } - - KeyRegExp(std::string const& key, std::string const& regExp) - : Key(key) - , RegExp(regExp) - { - } - - std::string Key; - cmsys::RegularExpression RegExp; - }; - - /// @brief Source file job - struct SourceJob - { - bool Moc = false; - bool Uic = false; - }; - - /// @brief MOC job - struct MocJobAuto - { - std::string SourceFile; - std::string BuildFileRel; - std::set<std::string> Depends; - }; - - /// @brief MOC job - struct MocJobIncluded : MocJobAuto - { - bool DependsValid = false; - std::string Includer; - std::string IncludeString; - }; - - /// @brief UIC job - struct UicJob - { - std::string SourceFile; - std::string BuildFileRel; - std::string Includer; - 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); - - // -- Settings file - void SettingsFileRead(cmMakefile* makefile); - bool SettingsFileWrite(); - bool SettingsChanged() const - { - return (this->MocSettingsChanged || this->RccSettingsChanged || - this->UicSettingsChanged); - } - - // -- Central processing - bool Process(); - - // -- Source parsing - bool ParseSourceFile(std::string const& absFilename, const SourceJob& job); - bool ParseHeaderFile(std::string const& absFilename, const SourceJob& job); - bool ParsePostprocess(); - - // -- Moc - bool MocEnabled() const { return !this->MocExecutable.empty(); } - bool MocSkip(std::string const& absFilename) const; - bool MocRequired(std::string const& contentText, - std::string* macroName = nullptr); - // Moc strings - std::string MocStringMacros() const; - std::string MocStringHeaders(std::string const& fileBase) const; - std::string MocFindIncludedHeader(std::string const& sourcePath, - std::string const& includeBase) const; - bool MocFindIncludedFile(std::string& absFile, std::string const& sourceFile, - std::string const& includeString) const; - // Moc depends - bool MocDependFilterPush(std::string const& key, std::string const& regExp); - void MocFindDepends(std::string const& absFilename, - std::string const& contentText, - std::set<std::string>& depends); - // Moc - bool MocParseSourceContent(std::string const& absFilename, - std::string const& contentText); - void MocParseHeaderContent(std::string const& absFilename, - std::string const& contentText); - - bool MocGenerateAll(); - bool MocGenerateFile(const MocJobAuto& mocJob, bool* generated = nullptr); - - // -- Uic - bool UicEnabled() const { return !this->UicExecutable.empty(); } - bool UicSkip(std::string const& absFilename) const; - bool UicParseContent(std::string const& fileName, - std::string const& contentText); - bool UicFindIncludedFile(std::string& absFile, std::string const& sourceFile, - std::string const& includeString); - 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; - std::string CurrentSourceDir; - std::string CurrentBinaryDir; - std::string AutogenBuildDir; - std::string AutogenIncludeDir; - // -- Qt environment - std::string QtMajorVersion; - std::string QtMinorVersion; - std::string MocExecutable; - std::string UicExecutable; - std::string RccExecutable; - // -- File lists - std::map<std::string, SourceJob> HeaderJobs; - std::map<std::string, SourceJob> SourceJobs; - std::vector<std::string> HeaderExtensions; - cmFilePathChecksum FilePathChecksum; - // -- Moc - bool MocSettingsChanged; - bool MocPredefsChanged; - bool MocRelaxedMode; - std::string MocCompFileRel; - std::string MocCompFileAbs; - std::string MocPredefsFileRel; - std::string MocPredefsFileAbs; - std::vector<std::string> MocSkipList; - std::vector<std::string> MocIncludePaths; - std::vector<std::string> MocIncludes; - std::vector<std::string> MocDefinitions; - std::vector<std::string> MocOptions; - std::vector<std::string> MocAllOptions; - std::vector<std::string> MocPredefsCmd; - std::vector<KeyRegExp> MocDependFilters; - std::vector<KeyRegExp> MocMacroFilters; - cmsys::RegularExpression MocRegExpInclude; - std::vector<std::unique_ptr<MocJobIncluded>> MocJobsIncluded; - std::vector<std::unique_ptr<MocJobAuto>> MocJobsAuto; - // -- Uic - bool UicSettingsChanged; - std::vector<std::string> UicSkipList; - std::vector<std::string> UicTargetOptions; - std::map<std::string, std::vector<std::string>> UicOptions; - 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/cmRemoveDefinitionsCommand.cxx b/Source/cmRemoveDefinitionsCommand.cxx index 8311b4b..8d3f688 100644 --- a/Source/cmRemoveDefinitionsCommand.cxx +++ b/Source/cmRemoveDefinitionsCommand.cxx @@ -16,7 +16,7 @@ bool cmRemoveDefinitionsCommand::InitialPass( } for (std::string const& i : args) { - this->Makefile->RemoveDefineFlag(i.c_str()); + this->Makefile->RemoveDefineFlag(i); } return true; } diff --git a/Source/cmSearchPath.cxx b/Source/cmSearchPath.cxx index a40c987..5b29868 100644 --- a/Source/cmSearchPath.cxx +++ b/Source/cmSearchPath.cxx @@ -155,7 +155,7 @@ void cmSearchPath::AddSuffixes(const std::vector<std::string>& suffixes) } // And now the original w/o any suffix - this->Paths.push_back(inPath); + this->Paths.push_back(std::move(inPath)); } } @@ -212,6 +212,6 @@ void cmSearchPath::AddPathInternal(const std::string& path, const char* base) // Insert the path if has not already been emitted. if (this->FC->SearchPathsEmitted.insert(collapsed).second) { - this->Paths.push_back(collapsed); + this->Paths.push_back(std::move(collapsed)); } } diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx index e923c22..1b04ca2 100644 --- a/Source/cmServer.cxx +++ b/Source/cmServer.cxx @@ -18,17 +18,19 @@ #include <cstdint> #include <iostream> #include <memory> +#include <mutex> #include <utility> 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 +60,8 @@ cmServer::cmServer(cmConnection* conn, bool supportExperimental) cmServer::~cmServer() { + Close(); + for (cmServerProtocol* p : this->SupportedProtocols) { delete p; } @@ -245,11 +249,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 +413,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 +421,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 +444,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 +473,6 @@ bool cmServerBase::Serve(std::string* errorMessage) return false; } - ServeThreadRunning = false; return true; } @@ -490,23 +486,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); + std::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 +512,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); + { + std::unique_lock<cm::shared_mutex> lock(ConnectionsMutex); + Connections.emplace_back(ownedConnection); + } ownedConnection->SetServer(this); } @@ -561,12 +554,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); + { + std::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 e6a7ae6..685542c 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 kSTART_MAGIC = "[== \"CMake Server\" ==["; static const std::string kEND_MAGIC = "]== \"CMake Server\" ==]"; diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx index 13b18c2..fbfaa40 100644 --- a/Source/cmServerProtocol.cxx +++ b/Source/cmServerProtocol.cxx @@ -8,9 +8,12 @@ #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmInstallGenerator.h" +#include "cmInstallTargetGenerator.h" #include "cmLinkLineComputer.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmProperty.h" #include "cmServer.h" #include "cmServerDictionary.h" #include "cmSourceFile.h" @@ -19,6 +22,8 @@ #include "cmStateSnapshot.h" #include "cmStateTypes.h" #include "cmSystemTools.h" +#include "cmTarget.h" +#include "cmTest.h" #include "cm_uv.h" #include "cmake.h" @@ -28,6 +33,7 @@ #include <functional> #include <limits> #include <map> +#include <memory> #include <set> #include <string> #include <unordered_map> @@ -97,7 +103,7 @@ void getCMakeInputs(const cmGlobalGenerator* gg, const std::string& sourceDir, std::string toAdd = lf; if (!sourceDir.empty()) { const std::string& relative = - cmSystemTools::RelativePath(sourceDir.c_str(), lf.c_str()); + cmSystemTools::RelativePath(sourceDir, lf); if (toAdd.size() > relative.size()) { toAdd = relative; } @@ -105,16 +111,16 @@ void getCMakeInputs(const cmGlobalGenerator* gg, const std::string& sourceDir, if (isInternal) { if (internalFiles) { - internalFiles->push_back(toAdd); + internalFiles->push_back(std::move(toAdd)); } } else { if (isTemporary) { if (tmpFiles) { - tmpFiles->push_back(toAdd); + tmpFiles->push_back(std::move(toAdd)); } } else { if (explicitFiles) { - explicitFiles->push_back(toAdd); + explicitFiles->push_back(std::move(toAdd)); } } } @@ -250,7 +256,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) @@ -260,8 +266,8 @@ static void setErrorMessage(std::string* errorMessage, const std::string& text) } } -static bool testHomeDirectory(cmState* state, std::string& value, - std::string* errorMessage) +static bool getOrTestHomeDirectory(cmState* state, std::string& value, + std::string* errorMessage) { const std::string cachedValue = std::string(state->GetCacheEntryValue("CMAKE_HOME_DIRECTORY")); @@ -282,9 +288,10 @@ static bool testHomeDirectory(cmState* state, std::string& value, return true; } -static bool testValue(cmState* state, const std::string& key, - std::string& value, const std::string& keyDescription, - std::string* errorMessage) +static bool getOrTestValue(cmState* state, const std::string& key, + std::string& value, + const std::string& keyDescription, + std::string* errorMessage) { const char* entry = state->GetCacheEntryValue(key); const std::string cachedValue = @@ -331,31 +338,31 @@ bool cmServerProtocol1::DoActivate(const cmServerRequest& request, cmState* state = cm->GetState(); // Check generator: - if (!testValue(state, "CMAKE_GENERATOR", generator, "generator", - errorMessage)) { + if (!getOrTestValue(state, "CMAKE_GENERATOR", generator, "generator", + errorMessage)) { return false; } // check extra generator: - if (!testValue(state, "CMAKE_EXTRA_GENERATOR", extraGenerator, - "extra generator", errorMessage)) { + if (!getOrTestValue(state, "CMAKE_EXTRA_GENERATOR", extraGenerator, + "extra generator", errorMessage)) { return false; } // check sourcedir: - if (!testHomeDirectory(state, sourceDirectory, errorMessage)) { + if (!getOrTestHomeDirectory(state, sourceDirectory, errorMessage)) { return false; } // check toolset: - if (!testValue(state, "CMAKE_GENERATOR_TOOLSET", toolset, "toolset", - errorMessage)) { + if (!getOrTestValue(state, "CMAKE_GENERATOR_TOOLSET", toolset, "toolset", + errorMessage)) { return false; } // check platform: - if (!testValue(state, "CMAKE_GENERATOR_PLATFORM", platform, "platform", - errorMessage)) { + if (!getOrTestValue(state, "CMAKE_GENERATOR_PLATFORM", platform, + "platform", errorMessage)) { return false; } } @@ -474,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!"); } @@ -538,8 +548,8 @@ cmServerResponse cmServerProtocol1::ProcessCMakeInputs( const cmake* cm = this->CMakeInstance(); const cmGlobalGenerator* gg = cm->GetGlobalGenerator(); const std::string cmakeRootDir = cmSystemTools::GetCMakeRoot(); - const std::string buildDir = cm->GetHomeOutputDirectory(); - const std::string sourceDir = cm->GetHomeDirectory(); + const std::string& buildDir = cm->GetHomeOutputDirectory(); + const std::string& sourceDir = cm->GetHomeDirectory(); Json::Value result = Json::objectValue; result[kSOURCE_DIRECTORY_KEY] = sourceDir; @@ -665,8 +675,7 @@ static Json::Value DumpSourceFileGroup(const LanguageData& data, Json::Value sourcesValue = Json::arrayValue; for (auto const& i : files) { - const std::string relPath = - cmSystemTools::RelativePath(baseDir.c_str(), i.c_str()); + const std::string relPath = cmSystemTools::RelativePath(baseDir, i); sourcesValue.append(relPath.size() < i.size() ? relPath : i); } @@ -690,24 +699,55 @@ static Json::Value DumpSourceFilesList( if (!fileData.Language.empty()) { const LanguageData& ld = languageDataMap.at(fileData.Language); cmLocalGenerator* lg = target->GetLocalGenerator(); + cmGeneratorExpressionInterpreter genexInterpreter( + lg, target, config, target->GetName(), fileData.Language); std::string compileFlags = ld.Flags; - if (const char* cflags = file->GetProperty("COMPILE_FLAGS")) { - cmGeneratorExpression ge; - auto cge = ge.Parse(cflags); - const char* processed = - cge->Evaluate(target->GetLocalGenerator(), config); - lg->AppendFlags(compileFlags, processed); + const std::string COMPILE_FLAGS("COMPILE_FLAGS"); + if (const char* cflags = file->GetProperty(COMPILE_FLAGS)) { + lg->AppendFlags(compileFlags, + genexInterpreter.Evaluate(cflags, COMPILE_FLAGS)); + } + const std::string COMPILE_OPTIONS("COMPILE_OPTIONS"); + if (const char* coptions = file->GetProperty(COMPILE_OPTIONS)) { + lg->AppendCompileOptions( + compileFlags, genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS)); } fileData.Flags = compileFlags; - fileData.IncludePathList = ld.IncludePathList; + // Add include directories from source file properties. + std::vector<std::string> includes; + + const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES"); + if (const char* cincludes = file->GetProperty(INCLUDE_DIRECTORIES)) { + const char* evaluatedIncludes = + genexInterpreter.Evaluate(cincludes, INCLUDE_DIRECTORIES); + lg->AppendIncludeDirectories(includes, evaluatedIncludes, *file); + + for (const auto& include : includes) { + fileData.IncludePathList.push_back(std::make_pair( + include, target->IsSystemIncludeDirectory(include, config))); + } + } + + fileData.IncludePathList.insert(fileData.IncludePathList.end(), + ld.IncludePathList.begin(), + ld.IncludePathList.end()); + const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS"); std::set<std::string> defines; - lg->AppendDefines(defines, file->GetProperty("COMPILE_DEFINITIONS")); + if (const char* defs = file->GetProperty(COMPILE_DEFINITIONS)) { + lg->AppendDefines( + defines, genexInterpreter.Evaluate(defs, COMPILE_DEFINITIONS)); + } + const std::string defPropName = "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config); - lg->AppendDefines(defines, file->GetProperty(defPropName)); + if (const char* config_defs = file->GetProperty(defPropName)) { + lg->AppendDefines(defines, genexInterpreter.Evaluate( + config_defs, COMPILE_DEFINITIONS)); + } + defines.insert(ld.Defines.begin(), ld.Defines.end()); fileData.SetDefines(defines); @@ -730,6 +770,108 @@ static Json::Value DumpSourceFilesList( return result; } +static Json::Value DumpCTestInfo(cmLocalGenerator* lg, cmTest* testInfo, + const std::string& config) +{ + 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(" "); + } + + // Remove any config specific variables from the output. + cmGeneratorExpression ge; + auto cge = ge.Parse(command.c_str()); + const char* processed = cge->Evaluate(lg, config); + + result[kCTEST_COMMAND] = processed; + + // 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; + + // Remove config variables from the value too. + auto cge_value = ge.Parse(prop.second.GetValue()); + const char* processed_value = cge_value->Evaluate(lg, config); + entry[kVALUE_KEY] = processed_value; + properties.append(entry); + } + result[kPROPERTIES_KEY] = properties; + + return result; +} + +static void DumpMakefileTests(cmLocalGenerator* lg, const std::string& config, + Json::Value* result) +{ + auto mf = lg->GetMakefile(); + std::vector<cmTest*> tests; + mf->GetTests(config, tests); + for (auto test : tests) { + Json::Value tmp = DumpCTestInfo(lg, test, config); + 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(); + DumpMakefileTests(lg, 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) { @@ -754,6 +896,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(); @@ -764,6 +908,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)) { + installPath = dest; + } else { + std::string installPrefix = + target->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX"); + installPath = installPrefix + '/' + dest; + } + + installPaths.append(installPath); + } + } + + result[kINSTALL_PATHS] = installPaths; + } + if (target->HaveWellDefinedOutputFiles()) { Json::Value artifacts = Json::arrayValue; artifacts.append( @@ -884,10 +1056,26 @@ static Json::Value DumpProjectList(const cmake* cm, std::string const& config) // Project structure information: const cmMakefile* mf = lg->GetMakefile(); + auto minVersion = mf->GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION"); + pObj[kMINIMUM_CMAKE_VERSION] = minVersion ? minVersion : ""; 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); } @@ -1141,6 +1329,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/cmSetPropertyCommand.cxx b/Source/cmSetPropertyCommand.cxx index 7efcc04..171b62e 100644 --- a/Source/cmSetPropertyCommand.cxx +++ b/Source/cmSetPropertyCommand.cxx @@ -167,7 +167,7 @@ bool cmSetPropertyCommand::HandleDirectoryMode() // Construct the directory name. Interpret relative paths with // respect to the current directory. std::string dir = *this->Names.begin(); - if (!cmSystemTools::FileIsFullPath(dir.c_str())) { + if (!cmSystemTools::FileIsFullPath(dir)) { dir = this->Makefile->GetCurrentSourceDirectory(); dir += "/"; dir += *this->Names.begin(); diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx index 0964bea..6792d66 100644 --- a/Source/cmSourceFile.cxx +++ b/Source/cmSourceFile.cxx @@ -12,8 +12,9 @@ #include "cmSystemTools.h" #include "cmake.h" -cmSourceFile::cmSourceFile(cmMakefile* mf, const std::string& name) - : Location(mf, name) +cmSourceFile::cmSourceFile(cmMakefile* mf, const std::string& name, + cmSourceFileLocationKind kind) + : Location(mf, name, kind) { this->CustomCommand = nullptr; this->FindFullPathFailed = false; @@ -110,7 +111,7 @@ std::string const& cmSourceFile::GetFullPath() const bool cmSourceFile::FindFullPath(std::string* error) { - // If thie method has already failed once do not try again. + // If this method has already failed once do not try again. if (this->FindFullPathFailed) { return false; } @@ -191,7 +192,7 @@ bool cmSourceFile::TryFullPath(const std::string& path, const std::string& ext) tryPath += "."; tryPath += ext; } - if (cmSystemTools::FileExists(tryPath.c_str())) { + if (cmSystemTools::FileExists(tryPath)) { this->FullPath = tryPath; return true; } diff --git a/Source/cmSourceFile.h b/Source/cmSourceFile.h index c2105d2..1516d98 100644 --- a/Source/cmSourceFile.h +++ b/Source/cmSourceFile.h @@ -7,6 +7,7 @@ #include "cmPropertyMap.h" #include "cmSourceFileLocation.h" +#include "cmSourceFileLocationKind.h" #include <string> #include <vector> @@ -27,7 +28,9 @@ public: * Construct with the makefile storing the source and the initial * name referencing it. */ - cmSourceFile(cmMakefile* mf, const std::string& name); + cmSourceFile( + cmMakefile* mf, const std::string& name, + cmSourceFileLocationKind kind = cmSourceFileLocationKind::Ambiguous); ~cmSourceFile(); @@ -120,7 +123,8 @@ private: #define CM_HEADER_REGEX "\\.(h|hh|h\\+\\+|hm|hpp|hxx|in|txx|inl)$" #define CM_SOURCE_REGEX \ - "\\.(C|M|c|c\\+\\+|cc|cpp|cxx|f|f90|for|fpp|ftn|m|mm|rc|def|r|odl|idl|hpj" \ + "\\.(C|M|c|c\\+\\+|cc|cpp|cxx|cu|f|f90|for|fpp|ftn|m|mm|rc|def|r|odl|idl|" \ + "hpj" \ "|bat)$" #define CM_RESOURCE_REGEX "\\.(pdf|plist|png|jpeg|jpg|storyboard|xcassets)$" diff --git a/Source/cmSourceFileLocation.cxx b/Source/cmSourceFileLocation.cxx index 4f337f2..bd8d318 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) @@ -29,17 +27,23 @@ cmSourceFileLocation::cmSourceFileLocation(const cmSourceFileLocation& loc) } cmSourceFileLocation::cmSourceFileLocation(cmMakefile const* mf, - const std::string& name) + const std::string& name, + cmSourceFileLocationKind kind) : Makefile(mf) { - this->AmbiguousDirectory = !cmSystemTools::FileIsFullPath(name.c_str()); + this->AmbiguousDirectory = !cmSystemTools::FileIsFullPath(name); this->AmbiguousExtension = true; this->Directory = cmSystemTools::GetFilenamePath(name); - if (cmSystemTools::FileIsFullPath(this->Directory.c_str())) { + if (cmSystemTools::FileIsFullPath(this->Directory)) { this->Directory = cmSystemTools::CollapseFullPath(this->Directory); } this->Name = cmSystemTools::GetFilenameName(name); - this->UpdateExtension(name); + if (kind == cmSourceFileLocationKind::Known) { + this->DirectoryUseSource(); + this->AmbiguousExtension = false; + } else { + this->UpdateExtension(name); + } } void cmSourceFileLocation::Update(cmSourceFileLocation const& loc) @@ -86,13 +90,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; @@ -112,7 +112,7 @@ void cmSourceFileLocation::UpdateExtension(const std::string& name) tryPath += "/"; } tryPath += this->Name; - if (cmSystemTools::FileExists(tryPath.c_str(), true)) { + if (cmSystemTools::FileExists(tryPath, true)) { // We found a source file named by the user on disk. Trust it's // extension. this->Name = cmSystemTools::GetFilenameName(name); @@ -149,14 +149,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/cmSourceFileLocation.h b/Source/cmSourceFileLocation.h index 467682d..f325e54 100644 --- a/Source/cmSourceFileLocation.h +++ b/Source/cmSourceFileLocation.h @@ -7,6 +7,8 @@ #include <string> +#include "cmSourceFileLocationKind.h" + class cmMakefile; /** \class cmSourceFileLocation @@ -26,7 +28,9 @@ public: * Construct for a source file created in a given cmMakefile * instance with an initial name. */ - cmSourceFileLocation(cmMakefile const* mf, const std::string& name); + cmSourceFileLocation( + cmMakefile const* mf, const std::string& name, + cmSourceFileLocationKind kind = cmSourceFileLocationKind::Ambiguous); cmSourceFileLocation(); cmSourceFileLocation(const cmSourceFileLocation& loc); @@ -38,12 +42,12 @@ public: bool Matches(cmSourceFileLocation const& loc); /** - * Explicity state that the source file is located in the source tree. + * Explicitly state that the source file is located in the source tree. */ void DirectoryUseSource(); /** - * Explicity state that the source file is located in the build tree. + * Explicitly state that the source file is located in the build tree. */ void DirectoryUseBinary(); diff --git a/Source/cmSourceFileLocationKind.h b/Source/cmSourceFileLocationKind.h new file mode 100644 index 0000000..dd4c6dd --- /dev/null +++ b/Source/cmSourceFileLocationKind.h @@ -0,0 +1,15 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmSourceFileLocationKind_h +#define cmSourceFileLocationKind_h + +enum class cmSourceFileLocationKind +{ + // The location is user-specified and may be ambiguous. + Ambiguous, + // The location is known to be at the given location; do not try to guess at + // extensions or absolute path. + Known +}; + +#endif diff --git a/Source/cmSourceGroup.cxx b/Source/cmSourceGroup.cxx index fba4c31..12ef62b 100644 --- a/Source/cmSourceGroup.cxx +++ b/Source/cmSourceGroup.cxx @@ -8,7 +8,7 @@ public: std::vector<cmSourceGroup> GroupChildren; }; -cmSourceGroup::cmSourceGroup(const char* name, const char* regex, +cmSourceGroup::cmSourceGroup(const std::string& name, const char* regex, const char* parentName) : Name(name) { @@ -60,24 +60,24 @@ 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) +bool cmSourceGroup::MatchesRegex(const std::string& name) { return this->GroupRegex.find(name); } -bool cmSourceGroup::MatchesFiles(const char* name) +bool cmSourceGroup::MatchesFiles(const std::string& name) const { - return this->GroupFiles.find(name) != this->GroupFiles.end(); + return this->GroupFiles.find(name) != this->GroupFiles.cend(); } void cmSourceGroup::AssignSource(const cmSourceFile* sf) @@ -95,21 +95,12 @@ void cmSourceGroup::AddChild(cmSourceGroup const& child) this->Internal->GroupChildren.push_back(child); } -cmSourceGroup* cmSourceGroup::LookupChild(const char* name) const +cmSourceGroup* cmSourceGroup::LookupChild(const std::string& name) { - // initializing iterators - std::vector<cmSourceGroup>::const_iterator iter = - this->Internal->GroupChildren.begin(); - const std::vector<cmSourceGroup>::const_iterator end = - this->Internal->GroupChildren.end(); - - // st - for (; iter != end; ++iter) { - std::string sgName = iter->GetName(); - + for (cmSourceGroup& group : this->Internal->GroupChildren) { // look if descenened is the one were looking for - if (sgName == name) { - return const_cast<cmSourceGroup*>(&(*iter)); // if it so return it + if (group.GetName() == name) { + return (&group); // if it so return it } } @@ -117,19 +108,13 @@ cmSourceGroup* cmSourceGroup::LookupChild(const char* name) const return nullptr; } -cmSourceGroup* cmSourceGroup::MatchChildrenFiles(const char* name) +cmSourceGroup* cmSourceGroup::MatchChildrenFiles(const std::string& name) { - // initializing iterators - std::vector<cmSourceGroup>::iterator iter = - this->Internal->GroupChildren.begin(); - std::vector<cmSourceGroup>::iterator end = - this->Internal->GroupChildren.end(); - if (this->MatchesFiles(name)) { return this; } - for (; iter != end; ++iter) { - cmSourceGroup* result = iter->MatchChildrenFiles(name); + for (cmSourceGroup& group : this->Internal->GroupChildren) { + cmSourceGroup* result = group.MatchChildrenFiles(name); if (result) { return result; } @@ -137,16 +122,10 @@ cmSourceGroup* cmSourceGroup::MatchChildrenFiles(const char* name) return nullptr; } -cmSourceGroup* cmSourceGroup::MatchChildrenRegex(const char* name) +cmSourceGroup* cmSourceGroup::MatchChildrenRegex(const std::string& name) { - // initializing iterators - std::vector<cmSourceGroup>::iterator iter = - this->Internal->GroupChildren.begin(); - std::vector<cmSourceGroup>::iterator end = - this->Internal->GroupChildren.end(); - - for (; iter != end; ++iter) { - cmSourceGroup* result = iter->MatchChildrenRegex(name); + for (cmSourceGroup& group : this->Internal->GroupChildren) { + cmSourceGroup* result = group.MatchChildrenRegex(name); if (result) { return result; } diff --git a/Source/cmSourceGroup.h b/Source/cmSourceGroup.h index e8bd697..b39f8dd 100644 --- a/Source/cmSourceGroup.h +++ b/Source/cmSourceGroup.h @@ -26,7 +26,7 @@ class cmSourceGroupInternals; class cmSourceGroup { public: - cmSourceGroup(const char* name, const char* regex, + cmSourceGroup(const std::string& name, const char* regex, const char* parentName = nullptr); cmSourceGroup(cmSourceGroup const& r); ~cmSourceGroup(); @@ -50,38 +50,38 @@ public: /** * Looks up child and returns it */ - cmSourceGroup* LookupChild(const char* name) const; + cmSourceGroup* LookupChild(const std::string& name); /** * 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. */ - bool MatchesRegex(const char* name); + bool MatchesRegex(const std::string& name); /** * Check if the given name matches this group's explicit file list. */ - bool MatchesFiles(const char* name); + bool MatchesFiles(const std::string& name) const; /** * Check if the given name matches this group's explicit file list * in children. */ - cmSourceGroup* MatchChildrenFiles(const char* name); + cmSourceGroup* MatchChildrenFiles(const std::string& name); /** * Check if the given name matches this group's regex in children. */ - cmSourceGroup* MatchChildrenRegex(const char* name); + cmSourceGroup* MatchChildrenRegex(const std::string& name); /** * Assign the given source file to this group. Used only by diff --git a/Source/cmSourceGroupCommand.cxx b/Source/cmSourceGroupCommand.cxx index 69983a8..8c9b63c 100644 --- a/Source/cmSourceGroupCommand.cxx +++ b/Source/cmSourceGroupCommand.cxx @@ -2,19 +2,21 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmSourceGroupCommand.h" +#include <algorithm> #include <set> -#include <sstream> #include <stddef.h> +#include <utility> #include "cmMakefile.h" #include "cmSourceGroup.h" #include "cmSystemTools.h" namespace { -const size_t RootIndex = 1; -const size_t FilesWithoutPrefixKeywordIndex = 2; -const size_t FilesWithPrefixKeywordIndex = 4; -const size_t PrefixKeywordIndex = 2; +const std::string kTreeOptionName = "TREE"; +const std::string kPrefixOptionName = "PREFIX"; +const std::string kFilesOptionName = "FILES"; +const std::string kRegexOptionName = "REGULAR_EXPRESSION"; +const std::string kSourceGroupOptionName = "<sg_name>"; std::vector<std::string> tokenizePath(const std::string& path) { @@ -26,7 +28,7 @@ std::string getFullFilePath(const std::string& currentPath, { std::string fullPath = path; - if (!cmSystemTools::FileIsFullPath(path.c_str())) { + if (!cmSystemTools::FileIsFullPath(path)) { fullPath = currentPath; fullPath += "/"; fullPath += path; @@ -71,14 +73,13 @@ std::string prepareFilePathForTree(const std::string& path, } std::vector<std::string> prepareFilesPathsForTree( - std::vector<std::string>::const_iterator begin, - std::vector<std::string>::const_iterator end, + const std::vector<std::string>& filesPaths, const std::string& currentSourceDir) { std::vector<std::string> prepared; - for (; begin != end; ++begin) { - prepared.push_back(prepareFilePathForTree(*begin, currentSourceDir)); + for (auto const& filePath : filesPaths) { + prepared.push_back(prepareFilePathForTree(filePath, currentSourceDir)); } return prepared; @@ -121,6 +122,57 @@ bool addFilesToItsSourceGroups(const std::string& root, class cmExecutionStatus; // cmSourceGroupCommand +cmSourceGroupCommand::ExpectedOptions +cmSourceGroupCommand::getExpectedOptions() const +{ + ExpectedOptions options; + + options.push_back(kTreeOptionName); + options.push_back(kPrefixOptionName); + options.push_back(kFilesOptionName); + options.push_back(kRegexOptionName); + + return options; +} + +bool cmSourceGroupCommand::isExpectedOption( + const std::string& argument, const ExpectedOptions& expectedOptions) +{ + return std::find(expectedOptions.begin(), expectedOptions.end(), argument) != + expectedOptions.end(); +} + +void cmSourceGroupCommand::parseArguments( + const std::vector<std::string>& args, + cmSourceGroupCommand::ParsedArguments& parsedArguments) +{ + const ExpectedOptions expectedOptions = getExpectedOptions(); + size_t i = 0; + + // at this point we know that args vector is not empty + + // if first argument is not one of expected options it's source group name + if (!isExpectedOption(args[0], expectedOptions)) { + // get source group name and go to next argument + parsedArguments[kSourceGroupOptionName].push_back(args[0]); + ++i; + } + + for (; i < args.size();) { + // get current option and increment index to go to next argument + const std::string& currentOption = args[i++]; + + // create current option entry in parsed arguments + std::vector<std::string>& currentOptionArguments = + parsedArguments[currentOption]; + + // collect option arguments while we won't find another expected option + while (i < args.size() && !isExpectedOption(args[i], expectedOptions)) { + currentOptionArguments.push_back(args[i++]); + } + } +} + bool cmSourceGroupCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { @@ -129,114 +181,98 @@ bool cmSourceGroupCommand::InitialPass(std::vector<std::string> const& args, return false; } - if (args[0] == "TREE") { - std::string error; + // If only two arguments are given, the pre-1.8 version of the + // command is being invoked. + if (args.size() == 2 && args[1] != "FILES") { + cmSourceGroup* sg = this->Makefile->GetOrCreateSourceGroup(args[0]); - if (!processTree(args, error)) { - this->SetError(error); + if (!sg) { + this->SetError("Could not create or find source group"); return false; } + sg->SetGroupRegex(args[1].c_str()); return true; } - cmSourceGroup* sg = this->Makefile->GetOrCreateSourceGroup(args[0]); + ParsedArguments parsedArguments; + std::string errorMsg; + + parseArguments(args, parsedArguments); - if (!sg) { - this->SetError("Could not create or find source group"); + if (!checkArgumentsPreconditions(parsedArguments, errorMsg)) { return false; } - // If only two arguments are given, the pre-1.8 version of the - // command is being invoked. - if (args.size() == 2 && args[1] != "FILES") { - sg->SetGroupRegex(args[1].c_str()); - return true; - } - // Process arguments. - bool doingFiles = false; - for (unsigned int i = 1; i < args.size(); ++i) { - if (args[i] == "REGULAR_EXPRESSION") { - // Next argument must specify the regex. - if (i + 1 < args.size()) { - ++i; - sg->SetGroupRegex(args[i].c_str()); - } else { - this->SetError("REGULAR_EXPRESSION argument given without a regex."); - return false; - } - doingFiles = false; - } else if (args[i] == "FILES") { - // Next arguments will specify files. - doingFiles = true; - } else if (doingFiles) { - // Convert name to full path and add to the group's list. - std::string src = args[i]; - if (!cmSystemTools::FileIsFullPath(src.c_str())) { + if (parsedArguments.find(kTreeOptionName) != parsedArguments.end()) { + if (!processTree(parsedArguments, errorMsg)) { + this->SetError(errorMsg); + return false; + } + } else { + if (parsedArguments.find(kSourceGroupOptionName) == + parsedArguments.end()) { + this->SetError("Missing source group name."); + return false; + } + + cmSourceGroup* sg = this->Makefile->GetOrCreateSourceGroup(args[0]); + + if (!sg) { + this->SetError("Could not create or find source group"); + return false; + } + + // handle regex + if (parsedArguments.find(kRegexOptionName) != parsedArguments.end()) { + const std::string& sgRegex = parsedArguments[kRegexOptionName].front(); + sg->SetGroupRegex(sgRegex.c_str()); + } + + // handle files + const std::vector<std::string>& filesArguments = + parsedArguments[kFilesOptionName]; + for (auto const& filesArg : filesArguments) { + std::string src = filesArg; + if (!cmSystemTools::FileIsFullPath(src)) { src = this->Makefile->GetCurrentSourceDirectory(); src += "/"; - src += args[i]; + src += filesArg; } src = cmSystemTools::CollapseFullPath(src); sg->AddGroupFile(src); - } else { - std::ostringstream err; - err << "Unknown argument \"" << args[i] << "\". " - << "Perhaps the FILES keyword is missing.\n"; - this->SetError(err.str()); - return false; } } return true; } -bool cmSourceGroupCommand::checkTreeArgumentsPreconditions( - const std::vector<std::string>& args, std::string& errorMsg) const +bool cmSourceGroupCommand::checkArgumentsPreconditions( + const ParsedArguments& parsedArguments, std::string& errorMsg) const { - if (args.size() == 1) { - errorMsg = "TREE argument given without a root."; - return false; - } - - if (args.size() < 3) { - errorMsg = "Missing FILES arguments."; - return false; - } - - if (args[FilesWithoutPrefixKeywordIndex] != "FILES" && - args[PrefixKeywordIndex] != "PREFIX") { - errorMsg = "Unknown argument \"" + args[2] + - "\". Perhaps the FILES keyword is missing.\n"; - return false; - } - - if (args[PrefixKeywordIndex] == "PREFIX" && - (args.size() < 5 || args[FilesWithPrefixKeywordIndex] != "FILES")) { - errorMsg = "Missing FILES arguments."; + if (!checkSingleParameterArgumentPreconditions(kPrefixOptionName, + parsedArguments, errorMsg) || + !checkSingleParameterArgumentPreconditions(kTreeOptionName, + parsedArguments, errorMsg) || + !checkSingleParameterArgumentPreconditions(kRegexOptionName, + parsedArguments, errorMsg)) { return false; } return true; } -bool cmSourceGroupCommand::processTree(const std::vector<std::string>& args, +bool cmSourceGroupCommand::processTree(ParsedArguments& parsedArguments, std::string& errorMsg) { - if (!checkTreeArgumentsPreconditions(args, errorMsg)) { - return false; - } - - const std::string root = cmSystemTools::CollapseFullPath(args[RootIndex]); - std::string prefix; - size_t filesBegin = FilesWithoutPrefixKeywordIndex + 1; - if (args[PrefixKeywordIndex] == "PREFIX") { - prefix = args[PrefixKeywordIndex + 1]; - filesBegin = FilesWithPrefixKeywordIndex + 1; - } + const std::string root = + cmSystemTools::CollapseFullPath(parsedArguments[kTreeOptionName].front()); + std::string prefix = parsedArguments[kPrefixOptionName].empty() + ? "" + : parsedArguments[kPrefixOptionName].front(); const std::vector<std::string> filesVector = - prepareFilesPathsForTree(args.begin() + filesBegin, args.end(), + prepareFilesPathsForTree(parsedArguments[kFilesOptionName], this->Makefile->GetCurrentSourceDirectory()); if (!rootIsPrefix(root, filesVector, errorMsg)) { @@ -253,3 +289,25 @@ bool cmSourceGroupCommand::processTree(const std::vector<std::string>& args, return true; } + +bool cmSourceGroupCommand::checkSingleParameterArgumentPreconditions( + const std::string& argument, const ParsedArguments& parsedArguments, + std::string& errorMsg) const +{ + ParsedArguments::const_iterator foundArgument = + parsedArguments.find(argument); + if (foundArgument != parsedArguments.end()) { + const std::vector<std::string>& optionArguments = foundArgument->second; + + if (optionArguments.empty()) { + errorMsg = argument + " argument given without an argument."; + return false; + } + if (optionArguments.size() > 1) { + errorMsg = "too many arguments passed to " + argument + "."; + return false; + } + } + + return true; +} diff --git a/Source/cmSourceGroupCommand.h b/Source/cmSourceGroupCommand.h index ed02ca5..ec5ad32 100644 --- a/Source/cmSourceGroupCommand.h +++ b/Source/cmSourceGroupCommand.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <map> #include <string> #include <vector> @@ -34,10 +35,24 @@ public: cmExecutionStatus& status) override; private: - bool processTree(const std::vector<std::string>& args, - std::string& errorMsg); - bool checkTreeArgumentsPreconditions(const std::vector<std::string>& args, - std::string& errorMsg) const; + typedef std::map<std::string, std::vector<std::string>> ParsedArguments; + typedef std::vector<std::string> ExpectedOptions; + + ExpectedOptions getExpectedOptions() const; + + bool isExpectedOption(const std::string& argument, + const ExpectedOptions& expectedOptions); + + void parseArguments(const std::vector<std::string>& args, + cmSourceGroupCommand::ParsedArguments& parsedArguments); + + bool processTree(ParsedArguments& parsedArguments, std::string& errorMsg); + + bool checkArgumentsPreconditions(const ParsedArguments& parsedArguments, + std::string& errorMsg) const; + bool checkSingleParameterArgumentPreconditions( + const std::string& argument, const ParsedArguments& parsedArguments, + std::string& errorMsg) const; }; #endif 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/cmState.cxx b/Source/cmState.cxx index 5957b5b..bb891b5 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -93,7 +93,7 @@ cmStateEnums::CacheEntryType cmState::StringToCacheEntryType(const char* s) bool cmState::IsCacheEntryType(std::string const& key) { for (int i = 0; cmCacheEntryTypes[i]; ++i) { - if (strcmp(key.c_str(), cmCacheEntryTypes[i]) == 0) { + if (key == cmCacheEntryTypes[i]) { return true; } } @@ -107,9 +107,9 @@ bool cmState::LoadCache(const std::string& path, bool internal, return this->CacheManager->LoadCache(path, internal, excludes, includes); } -bool cmState::SaveCache(const std::string& path) +bool cmState::SaveCache(const std::string& path, cmMessenger* messenger) { - return this->CacheManager->SaveCache(path); + return this->CacheManager->SaveCache(path, messenger); } bool cmState::DeleteCache(const std::string& path) @@ -514,9 +514,9 @@ void cmState::SetSourceDirectory(std::string const& sourceDirectory) cmSystemTools::ConvertToUnixSlashes(this->SourceDirectory); } -const char* cmState::GetSourceDirectory() const +std::string const& cmState::GetSourceDirectory() const { - return this->SourceDirectory.c_str(); + return this->SourceDirectory; } void cmState::SetBinaryDirectory(std::string const& binaryDirectory) @@ -595,9 +595,9 @@ unsigned int cmState::GetCacheMinorVersion() const return this->CacheManager->GetCacheMinorVersion(); } -const char* cmState::GetBinaryDirectory() const +std::string const& cmState::GetBinaryDirectory() const { - return this->BinaryDirectory.c_str(); + return this->BinaryDirectory; } cmStateSnapshot cmState::CreateBaseSnapshot() diff --git a/Source/cmState.h b/Source/cmState.h index e03ad89..6cbf82d 100644 --- a/Source/cmState.h +++ b/Source/cmState.h @@ -23,6 +23,7 @@ class cmCacheManager; class cmCommand; class cmPropertyDefinition; class cmStateSnapshot; +class cmMessenger; class cmState { @@ -59,7 +60,7 @@ public: std::set<std::string>& excludes, std::set<std::string>& includes); - bool SaveCache(const std::string& path); + bool SaveCache(const std::string& path, cmMessenger* messenger); bool DeleteCache(const std::string& path); @@ -137,9 +138,9 @@ public: const char* GetGlobalProperty(const std::string& prop); bool GetGlobalPropertyAsBool(const std::string& prop); - const char* GetSourceDirectory() const; + std::string const& GetSourceDirectory() const; void SetSourceDirectory(std::string const& sourceDirectory); - const char* GetBinaryDirectory() const; + std::string const& GetBinaryDirectory() const; void SetBinaryDirectory(std::string const& binaryDirectory); void SetWindowsShell(bool windowsShell); diff --git a/Source/cmStateSnapshot.cxx b/Source/cmStateSnapshot.cxx index bdef3e5..479ecd2 100644 --- a/Source/cmStateSnapshot.cxx +++ b/Source/cmStateSnapshot.cxx @@ -386,6 +386,12 @@ void cmStateSnapshot::InitializeFromParent() parent->BuildSystemDirectory->CompileOptionsBacktraces, this->Position->BuildSystemDirectory->CompileOptionsBacktraces, this->Position->CompileOptionsPosition); + + const char* include_regex = + parent->BuildSystemDirectory->Properties.GetPropertyValue( + "INCLUDE_REGULAR_EXPRESSION"); + this->Position->BuildSystemDirectory->Properties.SetProperty( + "INCLUDE_REGULAR_EXPRESSION", include_regex); } cmState* cmStateSnapshot::GetState() const diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 63c1452..88cfe81 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -3,6 +3,7 @@ #include "cmSystemTools.h" #include "cmAlgorithms.h" +#include "cmDuration.h" #include "cmProcessOutput.h" #include "cm_sys_stat.h" @@ -50,6 +51,10 @@ #include <windows.h> // include wincrypt.h after windows.h #include <wincrypt.h> + +#include <fcntl.h> /* _O_TEXT */ + +#include "cm_uv.h" #else #include <sys/time.h> #include <unistd.h> @@ -697,7 +702,7 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command, std::string* captureStdOut, std::string* captureStdErr, int* retVal, const char* dir, OutputOption outputflag, - double timeout, Encoding encoding) + cmDuration timeout, Encoding encoding) { std::vector<const char*> argv; argv.reserve(command.size() + 1); @@ -725,7 +730,7 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command, } assert(!captureStdErr || captureStdErr != captureStdOut); - cmsysProcess_SetTimeout(cp, timeout); + cmsysProcess_SetTimeout(cp, timeout.count()); cmsysProcess_Execute(cp); std::vector<char> tempStdOut; @@ -838,7 +843,7 @@ bool cmSystemTools::RunSingleCommand(const char* command, std::string* captureStdOut, std::string* captureStdErr, int* retVal, const char* dir, OutputOption outputflag, - double timeout) + cmDuration timeout) { if (s_DisableRunCommandOutput) { outputflag = OUTPUT_NONE; @@ -872,7 +877,7 @@ bool cmSystemTools::DoesFileExistWithExtensions( hname = name; hname += "."; hname += headerExt; - if (cmSystemTools::FileExists(hname.c_str())) { + if (cmSystemTools::FileExists(hname)) { return true; } } @@ -890,7 +895,7 @@ std::string cmSystemTools::FileExistsInParentDirectories(const char* fname, std::string prevDir; while (dir != prevDir) { std::string path = dir + "/" + file; - if (cmSystemTools::FileExists(path.c_str())) { + if (cmSystemTools::FileExists(path)) { return path; } if (dir.size() < strlen(toplevel)) { @@ -943,7 +948,55 @@ 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 + +void cmSystemTools::InitializeLibUV() +{ +#if defined(_WIN32) + // Perform libuv one-time initialization now, and then un-do its + // global _fmode setting so that using libuv does not change the + // default file text/binary mode. See libuv issue 840. + uv_loop_close(uv_default_loop()); +#ifdef _MSC_VER + _set_fmode(_O_TEXT); +#else + _fmode = _O_TEXT; +#endif #endif +} bool cmSystemTools::RenameFile(const char* oldname, const char* newname) { @@ -1101,7 +1154,7 @@ void cmSystemTools::Glob(const std::string& directory, for (i = 0; i < numf; i++) { std::string fname = d.GetFile(i); if (reg.find(fname)) { - files.push_back(fname); + files.push_back(std::move(fname)); } } } @@ -1273,6 +1326,9 @@ cmSystemTools::FileFormat cmSystemTools::GetFileFormat(const char* cext) if (ext == "java" || ext == ".java") { return cmSystemTools::JAVA_FILE_FORMAT; } + if (ext == "cu" || ext == ".cu") { + return cmSystemTools::CUDA_FILE_FORMAT; + } if (ext == "H" || ext == ".H" || ext == "h" || ext == ".h" || ext == "h++" || ext == ".h++" || ext == "hm" || ext == ".hm" || ext == "hpp" || ext == ".hpp" || ext == "hxx" || ext == ".hxx" || ext == "in" || @@ -1315,7 +1371,7 @@ bool cmSystemTools::Split(const char* s, std::vector<std::string>& l) return res; } -std::string cmSystemTools::ConvertToOutputPath(const char* path) +std::string cmSystemTools::ConvertToOutputPath(std::string const& path) { #if defined(_WIN32) && !defined(__CYGWIN__) if (s_ForceUnixPaths) { @@ -1352,15 +1408,16 @@ std::string cmSystemTools::ConvertToRunCommandPath(const char* path) } // compute the relative path from here to there -std::string cmSystemTools::RelativePath(const char* local, const char* remote) +std::string cmSystemTools::RelativePath(std::string const& local, + std::string const& remote) { if (!cmSystemTools::FileIsFullPath(local)) { cmSystemTools::Error("RelativePath must be passed a full path to local: ", - local); + local.c_str()); } if (!cmSystemTools::FileIsFullPath(remote)) { cmSystemTools::Error("RelativePath must be passed a full path to remote: ", - remote); + remote.c_str()); } return cmsys::SystemTools::RelativePath(local, remote); } @@ -1514,9 +1571,9 @@ bool cmSystemTools::CreateTar(const char* outFileName, a.SetMTime(mtime); a.SetVerbose(verbose); for (auto path : files) { - if (cmSystemTools::FileIsFullPath(path.c_str())) { + if (cmSystemTools::FileIsFullPath(path)) { // Get the relative path to the file. - path = cmSystemTools::RelativePath(cwd.c_str(), path.c_str()); + path = cmSystemTools::RelativePath(cwd, path); } if (!a.Add(path)) { break; @@ -1773,7 +1830,7 @@ bool cmSystemTools::ListTar(const char* outFileName, bool verbose) } int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line, - double timeout, std::vector<char>& out, + cmDuration timeout, std::vector<char>& out, std::vector<char>& err) { line.clear(); @@ -1821,7 +1878,9 @@ int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line, // No newlines found. Wait for more data from the process. int length; char* data; - int pipe = cmsysProcess_WaitForData(process, &data, &length, &timeout); + double timeoutAsDbl = timeout.count(); + int pipe = + cmsysProcess_WaitForData(process, &data, &length, &timeoutAsDbl); if (pipe == cmsysProcess_Pipe_Timeout) { // Timeout has been exceeded. return pipe; @@ -2052,8 +2111,12 @@ void cmSystemTools::FindCMakeResources(const char* argv0) (void)argv0; // ignore this on windows wchar_t modulepath[_MAX_PATH]; ::GetModuleFileNameW(NULL, modulepath, sizeof(modulepath)); - exe_dir = - cmSystemTools::GetFilenamePath(cmsys::Encoding::ToNarrow(modulepath)); + std::string path = cmsys::Encoding::ToNarrow(modulepath); + std::string realPath = cmSystemTools::GetRealPath(path, NULL); + if (realPath.empty()) { + realPath = path; + } + exe_dir = cmSystemTools::GetFilenamePath(realPath); #elif defined(__APPLE__) (void)argv0; // ignore this on OS X #define CM_EXE_PATH_LOCAL_SIZE 16384 @@ -2115,19 +2178,19 @@ void cmSystemTools::FindCMakeResources(const char* argv0) cmSystemToolsCMakeGUICommand = exe_dir; cmSystemToolsCMakeGUICommand += "/cmake-gui"; cmSystemToolsCMakeGUICommand += cmSystemTools::GetExecutableExtension(); - if (!cmSystemTools::FileExists(cmSystemToolsCMakeGUICommand.c_str())) { + if (!cmSystemTools::FileExists(cmSystemToolsCMakeGUICommand)) { cmSystemToolsCMakeGUICommand.clear(); } cmSystemToolsCMakeCursesCommand = exe_dir; cmSystemToolsCMakeCursesCommand += "/ccmake"; cmSystemToolsCMakeCursesCommand += cmSystemTools::GetExecutableExtension(); - if (!cmSystemTools::FileExists(cmSystemToolsCMakeCursesCommand.c_str())) { + if (!cmSystemTools::FileExists(cmSystemToolsCMakeCursesCommand)) { cmSystemToolsCMakeCursesCommand.clear(); } cmSystemToolsCMClDepsCommand = exe_dir; cmSystemToolsCMClDepsCommand += "/cmcldeps"; cmSystemToolsCMClDepsCommand += cmSystemTools::GetExecutableExtension(); - if (!cmSystemTools::FileExists(cmSystemToolsCMClDepsCommand.c_str())) { + if (!cmSystemTools::FileExists(cmSystemToolsCMClDepsCommand)) { cmSystemToolsCMClDepsCommand.clear(); } @@ -2142,7 +2205,7 @@ void cmSystemTools::FindCMakeResources(const char* argv0) } if (cmSystemToolsCMakeRoot.empty() || !cmSystemTools::FileExists( - (cmSystemToolsCMakeRoot + "/Modules/CMake.cmake").c_str())) { + (cmSystemToolsCMakeRoot + "/Modules/CMake.cmake"))) { // Build tree has "<build>/bin[/<config>]/cmake" and // "<build>/CMakeFiles/CMakeSourceDir.txt". std::string dir = cmSystemTools::GetFilenamePath(exe_dir); diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index e7082e6..a53afde 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include "cmCryptoHash.h" +#include "cmDuration.h" #include "cmProcessOutput.h" #include "cmsys/Process.h" #include "cmsys/SystemTools.hxx" // IWYU pragma: export @@ -59,7 +60,7 @@ public: * Set the function used by GUIs to display error messages * Function gets passed: message as a const char*, * title as a const char*, and a reference to bool that when - * set to false, will disable furthur messages (cancel). + * set to false, will disable further messages (cancel). */ static void SetMessageCallback(MessageCallback f, void* clientData = nullptr); @@ -167,7 +168,7 @@ public: * to be at the end of the string and it does not support ? * []... The optional argument type specifies what kind of files you * want to find. 0 means all files, -1 means directories, 1 means - * files only. This method returns true if search was succesfull. + * files only. This method returns true if search was successful. */ static bool SimpleGlob(const std::string& glob, std::vector<std::string>& files, int type = 0); @@ -225,11 +226,11 @@ public: int* retVal = nullptr, const char* dir = nullptr, OutputOption outputflag = OUTPUT_MERGE, - double timeout = 0.0); + cmDuration timeout = cmDuration::zero()); /** * In this version of RunSingleCommand, command[0] should be * the command to run, and each argument to the command should - * be in comand[1]...command[command.size()] + * be in command[1]...command[command.size()] */ static bool RunSingleCommand(std::vector<std::string> const& command, std::string* captureStdOut = nullptr, @@ -237,7 +238,7 @@ public: int* retVal = nullptr, const char* dir = nullptr, OutputOption outputflag = OUTPUT_MERGE, - double timeout = 0.0, + cmDuration timeout = cmDuration::zero(), Encoding encoding = cmProcessOutput::Auto); static std::string PrintSingleCommand(std::vector<std::string> const&); @@ -285,6 +286,7 @@ public: CXX_FILE_FORMAT, FORTRAN_FILE_FORMAT, JAVA_FILE_FORMAT, + CUDA_FILE_FORMAT, HEADER_FILE_FORMAT, RESOURCE_FILE_FORMAT, DEFINITION_FILE_FORMAT, @@ -342,7 +344,7 @@ public: /** a general output handler for cmsysProcess */ static int WaitForLine(cmsysProcess* process, std::string& line, - double timeout, std::vector<char>& out, + cmDuration timeout, std::vector<char>& out, std::vector<char>& err); /** Split a string on its newlines into multiple lines. Returns @@ -352,7 +354,7 @@ public: static bool GetForceUnixPaths() { return s_ForceUnixPaths; } // ConvertToOutputPath use s_ForceUnixPaths - static std::string ConvertToOutputPath(const char* path); + static std::string ConvertToOutputPath(std::string const& path); static void ConvertToOutputSlashes(std::string& path); // ConvertToRunCommandPath does not use s_ForceUnixPaths and should @@ -368,7 +370,8 @@ public: /a/b/c/d to /a/b/c1/d1 -> ../../c1/d1 from /usr/src to /usr/src/test/blah/foo.cpp -> test/blah/foo.cpp */ - static std::string RelativePath(const char* local, const char* remote); + static std::string RelativePath(std::string const& local, + std::string const& remote); /** Joins two paths while collapsing x/../ parts * For example CollapseCombinedPath("a/b/c", "../../d") results in "a/d" @@ -497,7 +500,15 @@ 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 + + /** Perform one-time initialization of libuv. */ + static void InitializeLibUV(); + private: static bool s_ForceUnixPaths; static bool s_RunCommandHideConsole; diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index c6cd502..cd11c4b 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -23,6 +23,7 @@ #include "cmProperty.h" #include "cmSourceFile.h" #include "cmSourceFileLocation.h" +#include "cmSourceFileLocationKind.h" #include "cmState.h" #include "cmStateDirectory.h" #include "cmStateSnapshot.h" @@ -176,6 +177,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,12 +240,14 @@ 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); this->SetPropertyDefault("AUTOMOC", nullptr); this->SetPropertyDefault("AUTOUIC", nullptr); this->SetPropertyDefault("AUTORCC", nullptr); + this->SetPropertyDefault("AUTOGEN_PARALLEL", nullptr); this->SetPropertyDefault("AUTOMOC_COMPILER_PREDEFINES", nullptr); this->SetPropertyDefault("AUTOMOC_DEPEND_FILTERS", nullptr); this->SetPropertyDefault("AUTOMOC_MACRO_NAMES", nullptr); @@ -279,6 +283,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); } @@ -495,7 +500,7 @@ void cmTarget::AddSources(std::vector<std::string> const& srcs) } if (!srcFiles.empty()) { cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); - this->Internal->SourceEntries.push_back(srcFiles); + this->Internal->SourceEntries.push_back(std::move(srcFiles)); this->Internal->SourceBacktraces.push_back(lfbt); } } @@ -603,7 +608,8 @@ public: cmSourceFile* cmTarget::AddSource(const std::string& src) { - cmSourceFileLocation sfl(this->Makefile, src); + cmSourceFileLocation sfl(this->Makefile, src, + cmSourceFileLocationKind::Known); if (std::find_if(this->Internal->SourceEntries.begin(), this->Internal->SourceEntries.end(), TargetPropertyEntryFinder(sfl)) == @@ -615,7 +621,8 @@ cmSourceFile* cmTarget::AddSource(const std::string& src) if (cmGeneratorExpression::Find(src) != std::string::npos) { return nullptr; } - return this->Makefile->GetOrCreateSource(src); + return this->Makefile->GetOrCreateSource(src, false, + cmSourceFileLocationKind::Known); } void cmTarget::AddLinkDirectory(const std::string& d) @@ -740,10 +747,12 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, const std::string& lib, return; } - cmTarget::LibraryID tmp; - tmp.first = lib; - tmp.second = llt; - this->OriginalLinkLibraries.push_back(tmp); + { + cmTarget::LibraryID tmp; + tmp.first = lib; + tmp.second = llt; + this->OriginalLinkLibraries.emplace_back(lib, llt); + } // Add the explicit dependency information for this target. This is // simply a set of libraries separated by ";". There should always @@ -852,40 +861,61 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) this->Makefile->GetBacktrace())) { return; } - if (prop == "MANUALLY_ADDED_DEPENDENCIES") { +#define MAKE_STATIC_PROP(PROP) static const std::string prop##PROP = #PROP + MAKE_STATIC_PROP(COMPILE_DEFINITIONS); + MAKE_STATIC_PROP(COMPILE_FEATURES); + MAKE_STATIC_PROP(COMPILE_OPTIONS); + MAKE_STATIC_PROP(CUDA_PTX_COMPILATION); + MAKE_STATIC_PROP(EXPORT_NAME); + MAKE_STATIC_PROP(IMPORTED_GLOBAL); + MAKE_STATIC_PROP(INCLUDE_DIRECTORIES); + MAKE_STATIC_PROP(LINK_LIBRARIES); + MAKE_STATIC_PROP(MANUALLY_ADDED_DEPENDENCIES); + MAKE_STATIC_PROP(NAME); + MAKE_STATIC_PROP(SOURCES); + MAKE_STATIC_PROP(TYPE); +#undef MAKE_STATIC_PROP + if (prop == propMANUALLY_ADDED_DEPENDENCIES) { std::ostringstream e; e << "MANUALLY_ADDED_DEPENDENCIES property is read-only\n"; this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); return; } - if (prop == "NAME") { + if (prop == propNAME) { std::ostringstream e; e << "NAME property is read-only\n"; this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); return; } - if (prop == "TYPE") { + if (prop == propTYPE) { std::ostringstream e; e << "TYPE property is read-only\n"; this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); return; } - if (prop == "EXPORT_NAME" && this->IsImported()) { + if (prop == propEXPORT_NAME && this->IsImported()) { std::ostringstream e; e << "EXPORT_NAME property can't be set on imported targets (\"" << this->Name << "\")\n"; this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); return; } - if (prop == "SOURCES" && this->IsImported()) { + if (prop == propSOURCES && this->IsImported()) { std::ostringstream e; e << "SOURCES property can't be set on imported targets (\"" << this->Name << "\")\n"; this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); return; } + if (prop == propIMPORTED_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") { + if (prop == propINCLUDE_DIRECTORIES) { this->Internal->IncludeDirectoriesEntries.clear(); this->Internal->IncludeDirectoriesBacktraces.clear(); if (value) { @@ -893,7 +923,7 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); this->Internal->IncludeDirectoriesBacktraces.push_back(lfbt); } - } else if (prop == "COMPILE_OPTIONS") { + } else if (prop == propCOMPILE_OPTIONS) { this->Internal->CompileOptionsEntries.clear(); this->Internal->CompileOptionsBacktraces.clear(); if (value) { @@ -901,7 +931,7 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); this->Internal->CompileOptionsBacktraces.push_back(lfbt); } - } else if (prop == "COMPILE_FEATURES") { + } else if (prop == propCOMPILE_FEATURES) { this->Internal->CompileFeaturesEntries.clear(); this->Internal->CompileFeaturesBacktraces.clear(); if (value) { @@ -909,7 +939,7 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); this->Internal->CompileFeaturesBacktraces.push_back(lfbt); } - } else if (prop == "COMPILE_DEFINITIONS") { + } else if (prop == propCOMPILE_DEFINITIONS) { this->Internal->CompileDefinitionsEntries.clear(); this->Internal->CompileDefinitionsBacktraces.clear(); if (value) { @@ -917,7 +947,7 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); this->Internal->CompileDefinitionsBacktraces.push_back(lfbt); } - } else if (prop == "LINK_LIBRARIES") { + } else if (prop == propLINK_LIBRARIES) { this->Internal->LinkImplementationPropertyEntries.clear(); this->Internal->LinkImplementationPropertyBacktraces.clear(); if (value) { @@ -925,7 +955,7 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) this->Internal->LinkImplementationPropertyEntries.push_back(value); this->Internal->LinkImplementationPropertyBacktraces.push_back(lfbt); } - } else if (prop == "SOURCES") { + } else if (prop == propSOURCES) { this->Internal->SourceEntries.clear(); this->Internal->SourceBacktraces.clear(); if (value) { @@ -933,10 +963,23 @@ 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 == propIMPORTED_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 */ - } else if (prop == "CUDA_PTX_COMPILATION" && + } else if (prop == propCUDA_PTX_COMPILATION && this->GetType() != cmStateEnums::OBJECT_LIBRARY) { std::ostringstream e; e << "CUDA_PTX_COMPILATION property can only be applied to OBJECT " @@ -977,6 +1020,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 +1194,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 +1223,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 +1253,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 +1268,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 +1337,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..4e716dc 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) { @@ -42,7 +33,7 @@ std::string cmTargetCompileDefinitionsCommand::Join( std::string defs; std::string sep; for (std::string const& it : content) { - if (cmHasLiteralPrefix(it.c_str(), "-D")) { + if (cmHasLiteralPrefix(it, "-D")) { defs += sep + it.substr(2); } else { defs += sep + it; @@ -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..fc546cc 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()); } @@ -48,7 +38,7 @@ std::string cmTargetIncludeDirectoriesCommand::Join( std::string prefix = this->Makefile->GetCurrentSourceDirectory() + std::string("/"); for (std::string const& it : content) { - if (cmSystemTools::FileIsFullPath(it.c_str()) || + if (cmSystemTools::FileIsFullPath(it) || cmGeneratorExpression::Find(it) == 0) { dirs += sep + it; } else { @@ -70,7 +60,7 @@ bool cmTargetIncludeDirectoriesCommand::HandleDirectContent( this->Makefile->GetCurrentSourceDirectory() + std::string("/"); std::set<std::string> sdirs; for (std::string const& it : content) { - if (cmSystemTools::FileIsFullPath(it.c_str()) || + if (cmSystemTools::FileIsFullPath(it) || cmGeneratorExpression::Find(it) == 0) { sdirs.insert(it); } else { @@ -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..9e4575a 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,8 +241,8 @@ 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 - // specifed that a library is both debug and optimized. (this check is + // and not use the lookup. As there may be the case where someone has + // specified 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) llt = GENERAL_LibraryType; @@ -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/cmTryCompileCommand.cxx b/Source/cmTryCompileCommand.cxx index b6bfbfa..3ff84ce 100644 --- a/Source/cmTryCompileCommand.cxx +++ b/Source/cmTryCompileCommand.cxx @@ -28,7 +28,7 @@ bool cmTryCompileCommand::InitialPass(std::vector<std::string> const& argv, // if They specified clean then we clean up what we can if (this->SrcFileSignature) { if (!this->Makefile->GetCMakeInstance()->GetDebugTryCompile()) { - this->CleanupFiles(this->BinaryDirectory.c_str()); + this->CleanupFiles(this->BinaryDirectory); } } return true; diff --git a/Source/cmTryRunCommand.cxx b/Source/cmTryRunCommand.cxx index dcaa493..9396138 100644 --- a/Source/cmTryRunCommand.cxx +++ b/Source/cmTryRunCommand.cxx @@ -4,8 +4,8 @@ #include "cmsys/FStream.hxx" #include <stdio.h> -#include <string.h> +#include "cmDuration.h" #include "cmMakefile.h" #include "cmState.h" #include "cmStateTypes.h" @@ -153,7 +153,7 @@ bool cmTryRunCommand::InitialPass(std::vector<std::string> const& argv, // if we created a directory etc, then cleanup after ourselves if (!this->Makefile->GetCMakeInstance()->GetDebugTryCompile()) { - this->CleanupFiles(this->BinaryDirectory.c_str()); + this->CleanupFiles(this->BinaryDirectory); } return true; } @@ -186,18 +186,19 @@ void cmTryRunCommand::RunExecutable(const std::string& runArgs, if (!runArgs.empty()) { finalCommand += runArgs; } - int timeout = 0; bool worked = cmSystemTools::RunSingleCommand( finalCommand.c_str(), out, out, &retVal, nullptr, - cmSystemTools::OUTPUT_NONE, timeout); + cmSystemTools::OUTPUT_NONE, cmDuration::zero()); // 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..eb70416 --- /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 <mutex> +#include <stdlib.h> + +#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<std::mutex> handleMutex; + + uv_handle_deleter() + : handleMutex(std::make_shared<std::mutex>()) + { + } + + void operator()(uv_async_t* handle) + { + std::lock_guard<std::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); + + std::lock_guard<std::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/cmUVSignalHackRAII.h b/Source/cmUVSignalHackRAII.h new file mode 100644 index 0000000..c019aea --- /dev/null +++ b/Source/cmUVSignalHackRAII.h @@ -0,0 +1,44 @@ +/* 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 "cm_uv.h" + +#if defined(CMAKE_USE_SYSTEM_LIBUV) && !defined(_WIN32) && \ + UV_VERSION_MAJOR == 1 && UV_VERSION_MINOR < 19 +#define CMAKE_UV_SIGNAL_HACK +#include "cmUVHandlePtr.h" +/* + libuv does not use SA_RESTART on its signal handler, but C++ streams + depend on it for reliable i/o operations. This RAII helper convinces + libuv to install its handler, and then revises the handler to add the + SA_RESTART flag. We use a distinct uv loop that never runs to avoid + ever really getting a callback. libuv may fill the hack loop's signal + pipe and then stop writing, but that won't break any real loops. + */ +class cmUVSignalHackRAII +{ + uv_loop_t HackLoop; + cm::uv_signal_ptr HackSignal; + static void HackCB(uv_signal_t*, int) {} +public: + cmUVSignalHackRAII() + { + uv_loop_init(&this->HackLoop); + this->HackSignal.init(this->HackLoop); + this->HackSignal.start(HackCB, SIGCHLD); + struct sigaction hack_sa; + sigaction(SIGCHLD, nullptr, &hack_sa); + if (!(hack_sa.sa_flags & SA_RESTART)) { + hack_sa.sa_flags |= SA_RESTART; + sigaction(SIGCHLD, &hack_sa, nullptr); + } + } + ~cmUVSignalHackRAII() + { + this->HackSignal.stop(); + uv_loop_close(&this->HackLoop); + } +}; +#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..ea012f6 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; @@ -23,7 +23,7 @@ bool cmUseMangledMesaCommand::InitialPass(std::vector<std::string> const& args, std::string glh = inputDir; glh += "/"; glh += "gl.h"; - if (!cmSystemTools::FileExists(glh.c_str())) { + if (!cmSystemTools::FileExists(glh)) { std::string e = "Bad path to Mesa, could not find: "; e += glh; e += " "; diff --git a/Source/cmUtilitySourceCommand.cxx b/Source/cmUtilitySourceCommand.cxx index 0ce437c..1140800 100644 --- a/Source/cmUtilitySourceCommand.cxx +++ b/Source/cmUtilitySourceCommand.cxx @@ -66,14 +66,14 @@ bool cmUtilitySourceCommand::InitialPass(std::vector<std::string> const& args, utilitySource = utilitySource + "/" + relativeSource; // If the directory doesn't exist, the source has not been included. - if (!cmSystemTools::FileExists(utilitySource.c_str())) { + if (!cmSystemTools::FileExists(utilitySource)) { return true; } // Make sure all the files exist in the source directory. while (arg != args.end()) { std::string file = utilitySource + "/" + *arg++; - if (!cmSystemTools::FileExists(file.c_str())) { + if (!cmSystemTools::FileExists(file)) { return true; } } diff --git a/Source/cmUtils.hxx b/Source/cmUtils.hxx index c5c767c..a7a3e81 100644 --- a/Source/cmUtils.hxx +++ b/Source/cmUtils.hxx @@ -7,7 +7,7 @@ // Use the make system's VERBOSE environment variable to enable // verbose output. This can be skipped by also setting CMAKE_NO_VERBOSE -// (which is set by the Eclipse and KDevelop generators). +// (which is set by the Eclipse generator). inline bool isCMakeVerbose() { return (cmSystemTools::HasEnv("VERBOSE") && 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/cmVariableWatchCommand.cxx b/Source/cmVariableWatchCommand.cxx index 9930086..e080df1 100644 --- a/Source/cmVariableWatchCommand.cxx +++ b/Source/cmVariableWatchCommand.cxx @@ -43,16 +43,14 @@ static void cmVariableWatchCommandVariableAccessed(const std::string& variable, std::string stack = makefile->GetProperty("LISTFILE_STACK"); if (!data->Command.empty()) { newLFF.Arguments.clear(); - newLFF.Arguments.push_back( - cmListFileArgument(variable, cmListFileArgument::Quoted, 9999)); - newLFF.Arguments.push_back( - cmListFileArgument(accessString, cmListFileArgument::Quoted, 9999)); - newLFF.Arguments.push_back(cmListFileArgument( - newValue ? newValue : "", cmListFileArgument::Quoted, 9999)); - newLFF.Arguments.push_back( - cmListFileArgument(currentListFile, cmListFileArgument::Quoted, 9999)); - newLFF.Arguments.push_back( - cmListFileArgument(stack, cmListFileArgument::Quoted, 9999)); + newLFF.Arguments.emplace_back(variable, cmListFileArgument::Quoted, 9999); + newLFF.Arguments.emplace_back(accessString, cmListFileArgument::Quoted, + 9999); + newLFF.Arguments.emplace_back(newValue ? newValue : "", + cmListFileArgument::Quoted, 9999); + newLFF.Arguments.emplace_back(currentListFile, cmListFileArgument::Quoted, + 9999); + newLFF.Arguments.emplace_back(stack, cmListFileArgument::Quoted, 9999); newLFF.Name = data->Command; newLFF.Line = 9999; cmExecutionStatus status; diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index c61902a..ec31bd6 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -15,8 +15,11 @@ #include "cmVisualStudioGeneratorOptions.h" #include "windows.h" +#include <iterator> #include <memory> // IWYU pragma: keep +static void ConvertToWindowsSlash(std::string& s); + static std::string cmVS10EscapeXML(std::string arg) { cmSystemTools::ReplaceString(arg, "&", "&"); @@ -37,8 +40,8 @@ static std::string cmVS10EscapeComment(std::string comment) // does "echo $CDATA" with no escapes. We must encode the string. // http://technet.microsoft.com/en-us/library/cc772462%28WS.10%29.aspx std::string echoable; - for (std::string::iterator c = comment.begin(); c != comment.end(); ++c) { - switch (*c) { + for (char c : comment) { + switch (c) { case '\r': break; case '\n': @@ -51,8 +54,9 @@ static std::string cmVS10EscapeComment(std::string comment) case '>': /* no break */ case '^': echoable += '^'; /* no break */ + CM_FALLTHROUGH; default: - echoable += *c; + echoable += c; break; } } @@ -65,11 +69,14 @@ static bool cmVS10IsTargetsFile(std::string const& path) return cmSystemTools::Strucmp(ext.c_str(), ".targets") == 0; } -static std::string computeProjectFileExtension(cmGeneratorTarget const* t) +static std::string computeProjectFileExtension(cmGeneratorTarget const* t, + const std::string& config) { std::string res; res = ".vcxproj"; - if (cmGlobalVisualStudioGenerator::TargetIsCSharpOnly(t)) { + std::string lang = t->GetLinkerLanguage(config); + if (cmGlobalVisualStudioGenerator::TargetIsCSharpOnly(t) || + lang == "CSharp") { res = ".csproj"; } return res; @@ -109,22 +116,6 @@ cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator( cmVisualStudio10TargetGenerator::~cmVisualStudio10TargetGenerator() { - for (OptionsMap::iterator i = this->ClOptions.begin(); - i != this->ClOptions.end(); ++i) { - delete i->second; - } - for (OptionsMap::iterator i = this->LinkOptions.begin(); - i != this->LinkOptions.end(); ++i) { - delete i->second; - } - for (OptionsMap::iterator i = this->CudaOptions.begin(); - i != this->CudaOptions.end(); ++i) { - delete i->second; - } - for (OptionsMap::iterator i = this->CudaLinkOptions.begin(); - i != this->CudaLinkOptions.end(); ++i) { - delete i->second; - } if (!this->BuildFileStream) { return; } @@ -198,8 +189,8 @@ void cmVisualStudio10TargetGenerator::Generate() this->GeneratorTarget->GetProperty("EXTERNAL_MSPROJECT")) { return; } - this->ProjectFileExtension = - computeProjectFileExtension(this->GeneratorTarget); + this->ProjectFileExtension = computeProjectFileExtension( + this->GeneratorTarget, *this->Configurations.begin()); if (this->ProjectFileExtension == ".vcxproj") { this->ProjectType = vcxproj; this->Managed = false; @@ -400,18 +391,17 @@ void cmVisualStudio10TargetGenerator::Generate() } std::vector<std::string> keys = this->GeneratorTarget->GetPropertyKeys(); - for (std::vector<std::string>::const_iterator keyIt = keys.begin(); - keyIt != keys.end(); ++keyIt) { + for (std::string const& keyIt : keys) { static const char* prefix = "VS_GLOBAL_"; - if (keyIt->find(prefix) != 0) + if (keyIt.find(prefix) != 0) continue; - std::string globalKey = keyIt->substr(strlen(prefix)); + std::string globalKey = keyIt.substr(strlen(prefix)); // Skip invalid or separately-handled properties. if (globalKey.empty() || globalKey == "PROJECT_TYPES" || globalKey == "ROOTNAMESPACE" || globalKey == "KEYWORD") { continue; } - const char* value = this->GeneratorTarget->GetProperty(*keyIt); + const char* value = this->GeneratorTarget->GetProperty(keyIt); if (!value) continue; this->WriteString("<", 2); @@ -494,7 +484,7 @@ void cmVisualStudio10TargetGenerator::Generate() std::string propsLocal; propsLocal += this->DefaultArtifactDir; propsLocal += "\\nasm.props"; - this->ConvertToWindowsSlash(propsLocal); + ConvertToWindowsSlash(propsLocal); this->Makefile->ConfigureFile(propsTemplate.c_str(), propsLocal.c_str(), false, true, true); std::string import = std::string("<Import Project=\"") + @@ -517,7 +507,7 @@ void cmVisualStudio10TargetGenerator::Generate() props = p; } if (!props.empty()) { - this->ConvertToWindowsSlash(props); + ConvertToWindowsSlash(props); this->WriteString("", 2); (*this->BuildFileStream) << "<Import Project=\"" << cmVS10EscapeXML(props) << "\"" @@ -573,22 +563,18 @@ void cmVisualStudio10TargetGenerator::Generate() } this->WriteString("</ImportGroup>\n", 1); if (this->ProjectType == csproj) { - for (std::vector<std::string>::const_iterator i = - this->Configurations.begin(); - i != this->Configurations.end(); ++i) { + for (std::string const& i : this->Configurations) { this->WriteString("<PropertyGroup Condition=\"'$(Configuration)' == '", 1); - (*this->BuildFileStream) << *i << "'\">\n"; - this->WriteEvents(*i); + (*this->BuildFileStream) << i << "'\">\n"; + this->WriteEvents(i); this->WriteString("</PropertyGroup>\n", 1); } // make sure custom commands are executed before build (if necessary) this->WriteString("<PropertyGroup>\n", 1); this->WriteString("<BuildDependsOn>\n", 2); - for (std::set<std::string>::const_iterator i = - this->CSharpCustomCommandNames.begin(); - i != this->CSharpCustomCommandNames.end(); ++i) { - this->WriteString(i->c_str(), 3); + for (std::string const& i : this->CSharpCustomCommandNames) { + this->WriteString(i.c_str(), 3); (*this->BuildFileStream) << ";\n"; } this->WriteString("$(BuildDependsOn)\n", 3); @@ -610,42 +596,37 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReferences() cmSystemTools::ExpandListArgument(vsDotNetReferences, references); } cmPropertyMap const& props = this->GeneratorTarget->Target->GetProperties(); - for (cmPropertyMap::const_iterator i = props.begin(); i != props.end(); - ++i) { - if (i->first.find("VS_DOTNET_REFERENCE_") == 0) { - std::string name = i->first.substr(20); + for (auto const& i : props) { + if (i.first.find("VS_DOTNET_REFERENCE_") == 0) { + std::string name = i.first.substr(20); if (!name.empty()) { - std::string path = i->second.GetValue(); + std::string path = i.second.GetValue(); if (!cmsys::SystemTools::FileIsFullPath(path)) { path = std::string(this->GeneratorTarget->Target->GetMakefile() ->GetCurrentSourceDirectory()) + "/" + path; } - this->ConvertToWindowsSlash(path); + ConvertToWindowsSlash(path); hintReferences.push_back(HintReference(name, path)); } } } if (!references.empty() || !hintReferences.empty()) { this->WriteString("<ItemGroup>\n", 1); - for (std::vector<std::string>::iterator ri = references.begin(); - ri != references.end(); ++ri) { + for (std::string const& ri : references) { // if the entry from VS_DOTNET_REFERENCES is an existing file, generate // a new hint-reference and name it from the filename - if (cmsys::SystemTools::FileExists(*ri, true)) { - std::string name = - cmsys::SystemTools::GetFilenameWithoutExtension(*ri); - std::string path = *ri; - this->ConvertToWindowsSlash(path); + if (cmsys::SystemTools::FileExists(ri, true)) { + std::string name = cmsys::SystemTools::GetFilenameWithoutExtension(ri); + std::string path = ri; + ConvertToWindowsSlash(path); hintReferences.push_back(HintReference(name, path)); } else { - this->WriteDotNetReference(*ri, ""); + this->WriteDotNetReference(ri, ""); } } - for (std::vector<std::pair<std::string, std::string>>::const_iterator i = - hintReferences.begin(); - i != hintReferences.end(); ++i) { - this->WriteDotNetReference(i->first, i->second); + for (const auto& i : hintReferences) { + this->WriteDotNetReference(i.first, i.second); } this->WriteString("</ItemGroup>\n", 1); } @@ -689,22 +670,19 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReferenceCustomTags( typedef std::map<std::string, std::string> CustomTags; CustomTags tags; cmPropertyMap const& props = this->GeneratorTarget->Target->GetProperties(); - for (cmPropertyMap::const_iterator i = props.begin(); i != props.end(); - ++i) { - if (i->first.find(refPropFullPrefix) == 0) { - std::string refTag = i->first.substr(refPropFullPrefix.length()); - std::string refVal = i->second.GetValue(); + for (const auto& i : props) { + if (i.first.find(refPropFullPrefix) == 0) { + std::string refTag = i.first.substr(refPropFullPrefix.length()); + std::string refVal = i.second.GetValue(); if (!refTag.empty() && !refVal.empty()) { tags[refTag] = refVal; } } } - for (CustomTags::const_iterator tag = tags.begin(); tag != tags.end(); - ++tag) { + for (auto const& tag : tags) { this->WriteString("<", 3); - (*this->BuildFileStream) << tag->first << ">" - << cmVS10EscapeXML(tag->second) << "</" - << tag->first << ">\n"; + (*this->BuildFileStream) << tag.first << ">" << cmVS10EscapeXML(tag.second) + << "</" << tag.first << ">\n"; } } @@ -715,13 +693,11 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup() if (!resxObjs.empty()) { this->WriteString("<ItemGroup>\n", 1); std::string srcDir = this->Makefile->GetCurrentSourceDirectory(); - this->ConvertToWindowsSlash(srcDir); - for (std::vector<cmSourceFile const*>::const_iterator oi = - resxObjs.begin(); - oi != resxObjs.end(); ++oi) { - std::string obj = (*oi)->GetFullPath(); + ConvertToWindowsSlash(srcDir); + for (cmSourceFile const* oi : resxObjs) { + std::string obj = oi->GetFullPath(); this->WriteString("<EmbeddedResource Include=\"", 2); - this->ConvertToWindowsSlash(obj); + ConvertToWindowsSlash(obj); bool useRelativePath = false; if (this->ProjectType == csproj && this->InSourceBuild) { // If we do an in-source build and the resource file is in a @@ -730,7 +706,7 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup() // visual studio does not show the file in the IDE. Sorry. if (obj.find(srcDir) == 0) { obj = this->ConvertPath(obj, true); - this->ConvertToWindowsSlash(obj); + ConvertToWindowsSlash(obj); useRelativePath = true; } } @@ -741,10 +717,8 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup() std::string hFileName = obj.substr(0, obj.find_last_of(".")) + ".h"; (*this->BuildFileStream) << hFileName << "</DependentUpon>\n"; - for (std::vector<std::string>::const_iterator i = - this->Configurations.begin(); - i != this->Configurations.end(); ++i) { - this->WritePlatformConfigTag("LogicalName", *i, 3); + for (std::string const& i : this->Configurations) { + this->WritePlatformConfigTag("LogicalName", i, 3); if (this->GeneratorTarget->GetProperty("VS_GLOBAL_ROOTNAMESPACE") || // Handle variant of VS_GLOBAL_<variable> for RootNamespace. this->GeneratorTarget->GetProperty("VS_GLOBAL_RootNamespace")) { @@ -756,7 +730,7 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup() } } else { std::string binDir = this->Makefile->GetCurrentBinaryDirectory(); - this->ConvertToWindowsSlash(binDir); + ConvertToWindowsSlash(binDir); // If the resource was NOT added using a relative path (which should // be the default), we have to provide a link here if (!useRelativePath) { @@ -775,13 +749,12 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup() } // Determine if this is a generated resource from a .Designer.cs file std::string designerResource = - cmSystemTools::GetFilenamePath((*oi)->GetFullPath()) + "/" + - cmSystemTools::GetFilenameWithoutLastExtension( - (*oi)->GetFullPath()) + + cmSystemTools::GetFilenamePath(oi->GetFullPath()) + "/" + + cmSystemTools::GetFilenameWithoutLastExtension(oi->GetFullPath()) + ".Designer.cs"; if (cmsys::SystemTools::FileExists(designerResource)) { std::string generator = "PublicResXFileCodeGenerator"; - if (const char* g = (*oi)->GetProperty("VS_RESOURCE_GENERATOR")) { + if (const char* g = oi->GetProperty("VS_RESOURCE_GENERATOR")) { generator = g; } if (!generator.empty()) { @@ -796,20 +769,19 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup() designerResource = cmsys::SystemTools::GetFilenameName(designerResource); } - this->ConvertToWindowsSlash(designerResource); + ConvertToWindowsSlash(designerResource); this->WriteString("<LastGenOutput>", 3); (*this->BuildFileStream) << designerResource << "</LastGenOutput>\n"; } } - const cmPropertyMap& props = (*oi)->GetProperties(); - for (cmPropertyMap::const_iterator p = props.begin(); p != props.end(); - ++p) { + const cmPropertyMap& props = oi->GetProperties(); + for (const auto& p : props) { static const std::string propNamePrefix = "VS_CSHARP_"; - if (p->first.find(propNamePrefix) == 0) { - std::string tagName = p->first.substr(propNamePrefix.length()); + if (p.first.find(propNamePrefix) == 0) { + std::string tagName = p.first.substr(propNamePrefix.length()); if (!tagName.empty()) { - std::string value = props.GetPropertyValue(p->first); + std::string value = props.GetPropertyValue(p.first); if (!value.empty()) { this->WriteString("<", 3); (*this->BuildFileStream) << tagName << ">"; @@ -833,19 +805,17 @@ void cmVisualStudio10TargetGenerator::WriteXamlFilesGroup() this->GeneratorTarget->GetXamlSources(xamlObjs, ""); if (!xamlObjs.empty()) { this->WriteString("<ItemGroup>\n", 1); - for (std::vector<cmSourceFile const*>::const_iterator oi = - xamlObjs.begin(); - oi != xamlObjs.end(); ++oi) { - std::string obj = (*oi)->GetFullPath(); + for (cmSourceFile const* oi : xamlObjs) { + std::string obj = oi->GetFullPath(); std::string xamlType; - const char* xamlTypeProperty = (*oi)->GetProperty("VS_XAML_TYPE"); + const char* xamlTypeProperty = oi->GetProperty("VS_XAML_TYPE"); if (xamlTypeProperty) { xamlType = xamlTypeProperty; } else { xamlType = "Page"; } - this->WriteSource(xamlType, *oi, ">\n"); + this->WriteSource(xamlType, oi, ">\n"); if (this->ProjectType == csproj && !this->InSourceBuild) { // add <Link> tag to written XAML source if necessary const std::string srcDir = this->Makefile->GetCurrentSourceDirectory(); @@ -859,7 +829,7 @@ void cmVisualStudio10TargetGenerator::WriteXamlFilesGroup() link = cmsys::SystemTools::GetFilenameName(obj); } if (!link.empty()) { - this->ConvertToWindowsSlash(link); + ConvertToWindowsSlash(link); this->WriteString("<Link>", 3); (*this->BuildFileStream) << link << "</Link>\n"; } @@ -1087,7 +1057,7 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesManaged( } std::string outDir = this->GeneratorTarget->GetDirectory(config) + "/"; - this->ConvertToWindowsSlash(outDir); + ConvertToWindowsSlash(outDir); this->WriteString("<OutputPath>", 2); (*this->BuildFileStream) << cmVS10EscapeXML(outDir) << "</OutputPath>\n"; @@ -1174,6 +1144,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( @@ -1258,7 +1237,7 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( d != ccg.GetDepends().end(); ++d) { std::string dep; if (this->LocalGenerator->GetRealDependency(*d, *i, dep)) { - this->ConvertToWindowsSlash(dep); + ConvertToWindowsSlash(dep); inputs << ";" << cmVS10EscapeXML(dep); } } @@ -1268,7 +1247,7 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( for (std::vector<std::string>::const_iterator o = ccg.GetOutputs().begin(); o != ccg.GetOutputs().end(); ++o) { std::string out = *o; - this->ConvertToWindowsSlash(out); + ConvertToWindowsSlash(out); outputs << sep << cmVS10EscapeXML(out); sep = ";"; } @@ -1346,7 +1325,7 @@ std::string cmVisualStudio10TargetGenerator::ConvertPath( : path.c_str(); } -void cmVisualStudio10TargetGenerator::ConvertToWindowsSlash(std::string& s) +static void ConvertToWindowsSlash(std::string& s) { // first convert all of the slashes std::string::size_type pos = 0; @@ -1373,7 +1352,7 @@ void cmVisualStudio10TargetGenerator::WriteGroups() si != sources.end(); ++si) { std::string const& source = si->Source->GetFullPath(); cmSourceGroup* sourceGroup = - this->Makefile->FindSourceGroup(source.c_str(), sourceGroups); + this->Makefile->FindSourceGroup(source, sourceGroups); groupsUsed.insert(sourceGroup); } @@ -1383,7 +1362,8 @@ void cmVisualStudio10TargetGenerator::WriteGroups() std::string path = this->LocalGenerator->GetCurrentBinaryDirectory(); path += "/"; path += this->Name; - path += computeProjectFileExtension(this->GeneratorTarget); + path += computeProjectFileExtension(this->GeneratorTarget, + *this->Configurations.begin()); path += ".filters"; cmGeneratedFileStream fout(path.c_str()); fout.SetCopyIfDifferent(true); @@ -1410,30 +1390,28 @@ void cmVisualStudio10TargetGenerator::WriteGroups() // Added files are images and the manifest. if (!this->AddedFiles.empty()) { this->WriteString("<ItemGroup>\n", 1); - for (std::vector<std::string>::const_iterator oi = - this->AddedFiles.begin(); - oi != this->AddedFiles.end(); ++oi) { + for (std::string const& oi : this->AddedFiles) { std::string fileName = - cmSystemTools::LowerCase(cmSystemTools::GetFilenameName(*oi)); + cmSystemTools::LowerCase(cmSystemTools::GetFilenameName(oi)); if (fileName == "wmappmanifest.xml") { this->WriteString("<XML Include=\"", 2); - (*this->BuildFileStream) << *oi << "\">\n"; + (*this->BuildFileStream) << oi << "\">\n"; this->WriteString("<Filter>Resource Files</Filter>\n", 3); this->WriteString("</XML>\n", 2); } else if (cmSystemTools::GetFilenameExtension(fileName) == ".appxmanifest") { this->WriteString("<AppxManifest Include=\"", 2); - (*this->BuildFileStream) << *oi << "\">\n"; + (*this->BuildFileStream) << oi << "\">\n"; this->WriteString("<Filter>Resource Files</Filter>\n", 3); this->WriteString("</AppxManifest>\n", 2); } else if (cmSystemTools::GetFilenameExtension(fileName) == ".pfx") { this->WriteString("<None Include=\"", 2); - (*this->BuildFileStream) << *oi << "\">\n"; + (*this->BuildFileStream) << oi << "\">\n"; this->WriteString("<Filter>Resource Files</Filter>\n", 3); this->WriteString("</None>\n", 2); } else { this->WriteString("<Image Include=\"", 2); - (*this->BuildFileStream) << *oi << "\">\n"; + (*this->BuildFileStream) << oi << "\">\n"; this->WriteString("<Filter>Resource Files</Filter>\n", 3); this->WriteString("</Image>\n", 2); } @@ -1445,12 +1423,10 @@ void cmVisualStudio10TargetGenerator::WriteGroups() this->GeneratorTarget->GetResxSources(resxObjs, ""); if (!resxObjs.empty()) { this->WriteString("<ItemGroup>\n", 1); - for (std::vector<cmSourceFile const*>::const_iterator oi = - resxObjs.begin(); - oi != resxObjs.end(); ++oi) { - std::string obj = (*oi)->GetFullPath(); + for (cmSourceFile const* oi : resxObjs) { + std::string obj = oi->GetFullPath(); this->WriteString("<EmbeddedResource Include=\"", 2); - this->ConvertToWindowsSlash(obj); + ConvertToWindowsSlash(obj); (*this->BuildFileStream) << cmVS10EscapeXML(obj) << "\">\n"; this->WriteString("<Filter>Resource Files</Filter>\n", 3); this->WriteString("</EmbeddedResource>\n", 2); @@ -1459,11 +1435,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_"; @@ -1504,16 +1483,15 @@ void cmVisualStudio10TargetGenerator::AddMissingSourceGroups( std::set<cmSourceGroup*>& groupsUsed, const std::vector<cmSourceGroup>& allGroups) { - for (std::vector<cmSourceGroup>::const_iterator current = allGroups.begin(); - current != allGroups.end(); ++current) { - std::vector<cmSourceGroup> const& children = current->GetGroupChildren(); + for (cmSourceGroup const& current : allGroups) { + std::vector<cmSourceGroup> const& children = current.GetGroupChildren(); if (children.empty()) { continue; // the group is really empty } this->AddMissingSourceGroups(groupsUsed, children); - cmSourceGroup* current_ptr = const_cast<cmSourceGroup*>(&(*current)); + cmSourceGroup* current_ptr = const_cast<cmSourceGroup*>(¤t); if (groupsUsed.find(current_ptr) != groupsUsed.end()) { continue; // group has already been added to set } @@ -1542,18 +1520,17 @@ void cmVisualStudio10TargetGenerator::WriteGroupSources( std::vector<cmSourceGroup>& sourceGroups) { this->WriteString("<ItemGroup>\n", 1); - for (ToolSources::const_iterator s = sources.begin(); s != sources.end(); - ++s) { - cmSourceFile const* sf = s->SourceFile; + for (ToolSource const& s : sources) { + cmSourceFile const* sf = s.SourceFile; std::string const& source = sf->GetFullPath(); cmSourceGroup* sourceGroup = - this->Makefile->FindSourceGroup(source.c_str(), sourceGroups); - const char* filter = sourceGroup->GetFullName(); + this->Makefile->FindSourceGroup(source, sourceGroups); + std::string const& filter = sourceGroup->GetFullName(); this->WriteString("<", 2); - std::string path = this->ConvertPath(source, s->RelativePath); - this->ConvertToWindowsSlash(path); + std::string path = this->ConvertPath(source, s.RelativePath); + 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 +1569,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; @@ -1622,7 +1601,7 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(cmSourceFile const* sf) sourceLink = cmsys::SystemTools::GetFilenameName(fullFileName); } if (!sourceLink.empty()) { - this->ConvertToWindowsSlash(sourceLink); + ConvertToWindowsSlash(sourceLink); } } } @@ -1658,6 +1637,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 +1656,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 +1785,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) @@ -1878,7 +1873,7 @@ void cmVisualStudio10TargetGenerator::WriteSource(std::string const& tool, this->GlobalGenerator->PathTooLong(this->GeneratorTarget, sf, sourceRel); } } - this->ConvertToWindowsSlash(sourceFile); + ConvertToWindowsSlash(sourceFile); this->WriteString("<", 2); (*this->BuildFileStream) << tool << " Include=\"" << cmVS10EscapeXML(sourceFile) << "\"" @@ -1903,11 +1898,9 @@ void cmVisualStudio10TargetGenerator::WriteAllSources() std::vector<cmGeneratorTarget::AllConfigSource> const& sources = this->GeneratorTarget->GetAllConfigSources(); - for (std::vector<cmGeneratorTarget::AllConfigSource>::const_iterator si = - sources.begin(); - si != sources.end(); ++si) { + for (cmGeneratorTarget::AllConfigSource const& si : sources) { std::string tool; - switch (si->Kind) { + switch (si.Kind) { case cmGeneratorTarget::SourceKindAppManifest: tool = "AppxManifest"; break; @@ -1926,17 +1919,17 @@ void cmVisualStudio10TargetGenerator::WriteAllSources() // then vs10 will use it in the build, and we have to list it as // None instead of Object. std::vector<cmSourceFile*> const* d = - this->GeneratorTarget->GetSourceDepends(si->Source); + this->GeneratorTarget->GetSourceDepends(si.Source); if (d && !d->empty()) { tool = "None"; } } break; case cmGeneratorTarget::SourceKindExtra: - this->WriteExtraSource(si->Source); + this->WriteExtraSource(si.Source); break; case cmGeneratorTarget::SourceKindHeader: - this->WriteHeaderSource(si->Source); + this->WriteHeaderSource(si.Source); break; case cmGeneratorTarget::SourceKindIDL: tool = "Midl"; @@ -1948,7 +1941,7 @@ void cmVisualStudio10TargetGenerator::WriteAllSources() tool = "None"; break; case cmGeneratorTarget::SourceKindObjectSource: { - const std::string& lang = si->Source->GetLanguage(); + const std::string& lang = si.Source->GetLanguage(); if (lang == "C" || lang == "CXX") { tool = "ClCompile"; } else if (lang == "ASM_MASM" && @@ -1977,16 +1970,16 @@ void cmVisualStudio10TargetGenerator::WriteAllSources() if (!tool.empty()) { // Compute set of configurations to exclude, if any. - std::vector<size_t> const& include_configs = si->Configs; + std::vector<size_t> const& include_configs = si.Configs; std::vector<size_t> exclude_configs; std::set_difference(all_configs.begin(), all_configs.end(), include_configs.begin(), include_configs.end(), std::back_inserter(exclude_configs)); - if (si->Kind == cmGeneratorTarget::SourceKindObjectSource) { + if (si.Kind == cmGeneratorTarget::SourceKindObjectSource) { // FIXME: refactor generation to avoid tracking XML syntax state. - this->WriteSource(tool, si->Source, " "); - bool have_nested = this->OutputSourceSpecificFlags(si->Source); + this->WriteSource(tool, si.Source, ""); + bool have_nested = this->OutputSourceSpecificFlags(si.Source); if (!exclude_configs.empty()) { if (!have_nested) { (*this->BuildFileStream) << ">\n"; @@ -2001,12 +1994,12 @@ void cmVisualStudio10TargetGenerator::WriteAllSources() (*this->BuildFileStream) << " />\n"; } } else if (!exclude_configs.empty()) { - this->WriteSource(tool, si->Source, ">\n"); + this->WriteSource(tool, si.Source, ">\n"); this->WriteExcludeFromBuild(exclude_configs); this->WriteString("</", 2); (*this->BuildFileStream) << tool << ">\n"; } else { - this->WriteSource(tool, si->Source); + this->WriteSource(tool, si.Source); } } } @@ -2029,17 +2022,32 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( } std::string flags; bool configDependentFlags = false; + std::string options; + bool configDependentOptions = false; std::string defines; + bool configDependentDefines = false; + std::string includes; + bool configDependentIncludes = false; if (const char* cflags = sf.GetProperty("COMPILE_FLAGS")) { - - if (cmGeneratorExpression::Find(cflags) != std::string::npos) { - configDependentFlags = true; - } + configDependentFlags = + cmGeneratorExpression::Find(cflags) != std::string::npos; flags += cflags; } + if (const char* coptions = sf.GetProperty("COMPILE_OPTIONS")) { + configDependentOptions = + cmGeneratorExpression::Find(coptions) != std::string::npos; + options += coptions; + } if (const char* cdefs = sf.GetProperty("COMPILE_DEFINITIONS")) { + configDependentDefines = + cmGeneratorExpression::Find(cdefs) != std::string::npos; defines += cdefs; } + if (const char* cincludes = sf.GetProperty("INCLUDE_DIRECTORIES")) { + configDependentIncludes = + cmGeneratorExpression::Find(cincludes) != std::string::npos; + includes += cincludes; + } std::string lang = this->GlobalGenerator->GetLanguageFromExtension(sf.GetExtension().c_str()); std::string sourceLang = this->LocalGenerator->GetSourceFileLanguage(sf); @@ -2072,14 +2080,18 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( (*this->BuildFileStream) << firstString; firstString = ""; hasFlags = true; - this->WriteString("<ObjectFileName>", 3); - (*this->BuildFileStream) << "$(IntDir)/" << objectName - << "</ObjectFileName>\n"; + if (lang == "CUDA") { + this->WriteString("<CompileOut>", 3); + (*this->BuildFileStream) << "$(IntDir)/" << objectName + << "</CompileOut>\n"; + } else { + this->WriteString("<ObjectFileName>", 3); + (*this->BuildFileStream) << "$(IntDir)/" << objectName + << "</ObjectFileName>\n"; + } } - for (std::vector<std::string>::const_iterator config = - this->Configurations.begin(); - config != this->Configurations.end(); ++config) { - std::string configUpper = cmSystemTools::UpperCase(*config); + for (std::string const& config : this->Configurations) { + std::string configUpper = cmSystemTools::UpperCase(config); std::string configDefines = defines; std::string defPropName = "COMPILE_DEFINITIONS_"; defPropName += configUpper; @@ -2087,12 +2099,14 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( if (!configDefines.empty()) { configDefines += ";"; } + configDependentDefines |= + cmGeneratorExpression::Find(ccdefs) != std::string::npos; configDefines += ccdefs; } // if we have flags or defines for this config then // use them - if (!flags.empty() || configDependentFlags || !configDefines.empty() || - compileAs || noWinRT) { + if (!flags.empty() || !options.empty() || !configDefines.empty() || + !includes.empty() || compileAs || noWinRT) { (*this->BuildFileStream) << firstString; firstString = ""; // only do firstString once hasFlags = true; @@ -2113,6 +2127,9 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( } else if (srclang == "CSharp") { flagtable = gg->GetCSharpFlagTable(); } + cmGeneratorExpressionInterpreter genexInterpreter( + this->LocalGenerator, this->GeneratorTarget, config, + this->GeneratorTarget->GetName(), lang); cmVisualStudioGeneratorOptions clOptions( this->LocalGenerator, cmVisualStudioGeneratorOptions::Compiler, flagtable, 0, this); @@ -2123,25 +2140,45 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( clOptions.AddFlag("CompileAsWinRT", "false"); } if (configDependentFlags) { - cmGeneratorExpression ge; - std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(flags); - std::string evaluatedFlags = cge->Evaluate( - this->LocalGenerator, *config, false, this->GeneratorTarget); - clOptions.Parse(evaluatedFlags.c_str()); + clOptions.Parse(genexInterpreter.Evaluate(flags, "COMPILE_FLAGS")); } else { clOptions.Parse(flags.c_str()); } - if (clOptions.HasFlag("AdditionalIncludeDirectories")) { - clOptions.AppendFlag("AdditionalIncludeDirectories", - "%(AdditionalIncludeDirectories)"); + if (!options.empty()) { + std::string expandedOptions; + if (configDependentOptions) { + this->LocalGenerator->AppendCompileOptions( + expandedOptions, + genexInterpreter.Evaluate(options, "COMPILE_OPTIONS")); + } else { + this->LocalGenerator->AppendCompileOptions(expandedOptions, options); + } + clOptions.Parse(expandedOptions.c_str()); } if (clOptions.HasFlag("DisableSpecificWarnings")) { clOptions.AppendFlag("DisableSpecificWarnings", "%(DisableSpecificWarnings)"); } - clOptions.AddDefines(configDefines.c_str()); - clOptions.SetConfiguration((*config).c_str()); + if (configDependentDefines) { + clOptions.AddDefines( + genexInterpreter.Evaluate(configDefines, "COMPILE_DEFINITIONS")); + } else { + clOptions.AddDefines(configDefines.c_str()); + } + std::vector<std::string> includeList; + if (configDependentIncludes) { + this->LocalGenerator->AppendIncludeDirectories( + includeList, + genexInterpreter.Evaluate(includes, "INCLUDE_DIRECTORIES"), *source); + } else { + this->LocalGenerator->AppendIncludeDirectories(includeList, includes, + *source); + } + clOptions.AddIncludes(includeList); + clOptions.SetConfiguration(config.c_str()); clOptions.PrependInheritedString("AdditionalOptions"); + clOptions.OutputAdditionalIncludeDirectories(*this->BuildFileStream, + " ", "\n", lang); clOptions.OutputFlagMap(*this->BuildFileStream, " "); clOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ", "\n", lang); @@ -2182,12 +2219,11 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( void cmVisualStudio10TargetGenerator::WriteExcludeFromBuild( std::vector<size_t> const& exclude_configs) { - for (std::vector<size_t>::const_iterator ci = exclude_configs.begin(); - ci != exclude_configs.end(); ++ci) { + for (size_t ci : exclude_configs) { this->WriteString("", 3); (*this->BuildFileStream) << "<ExcludedFromBuild Condition=\"'$(Configuration)|$(Platform)'=='" - << cmVS10EscapeXML(this->Configurations[*ci]) << "|" + << cmVS10EscapeXML(this->Configurations[ci]) << "|" << cmVS10EscapeXML(this->Platform) << "'\">true</ExcludedFromBuild>\n"; } } @@ -2206,11 +2242,9 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions() this->WriteString("<_ProjectFileVersion>10.0.20506.1" "</_ProjectFileVersion>\n", 2); - for (std::vector<std::string>::const_iterator config = - this->Configurations.begin(); - config != this->Configurations.end(); ++config) { + for (std::string const& config : this->Configurations) { if (ttype >= cmStateEnums::UTILITY) { - this->WritePlatformConfigTag("IntDir", *config, 2); + this->WritePlatformConfigTag("IntDir", config, 2); *this->BuildFileStream << "$(Platform)\\$(Configuration)\\$(ProjectName)\\" << "</IntDir>\n"; @@ -2218,7 +2252,7 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions() std::string intermediateDir = this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); intermediateDir += "/"; - intermediateDir += *config; + intermediateDir += config; intermediateDir += "/"; std::string outDir; std::string targetNameFull; @@ -2227,22 +2261,22 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions() targetNameFull = this->GeneratorTarget->GetName(); targetNameFull += ".lib"; } else { - outDir = this->GeneratorTarget->GetDirectory(*config) + "/"; - targetNameFull = this->GeneratorTarget->GetFullName(*config); + outDir = this->GeneratorTarget->GetDirectory(config) + "/"; + targetNameFull = this->GeneratorTarget->GetFullName(config); } - this->ConvertToWindowsSlash(intermediateDir); - this->ConvertToWindowsSlash(outDir); + ConvertToWindowsSlash(intermediateDir); + ConvertToWindowsSlash(outDir); - this->WritePlatformConfigTag("OutDir", *config, 2); + this->WritePlatformConfigTag("OutDir", config, 2); *this->BuildFileStream << cmVS10EscapeXML(outDir) << "</OutDir>\n"; - this->WritePlatformConfigTag("IntDir", *config, 2); + this->WritePlatformConfigTag("IntDir", config, 2); *this->BuildFileStream << cmVS10EscapeXML(intermediateDir) << "</IntDir>\n"; if (const char* workingDir = this->GeneratorTarget->GetProperty( "VS_DEBUGGER_WORKING_DIRECTORY")) { - this->WritePlatformConfigTag("LocalDebuggerWorkingDirectory", *config, + this->WritePlatformConfigTag("LocalDebuggerWorkingDirectory", config, 2); *this->BuildFileStream << cmVS10EscapeXML(workingDir) << "</LocalDebuggerWorkingDirectory>\n"; @@ -2250,7 +2284,7 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions() std::string name = cmSystemTools::GetFilenameWithoutLastExtension(targetNameFull); - this->WritePlatformConfigTag("TargetName", *config, 2); + this->WritePlatformConfigTag("TargetName", config, 2); *this->BuildFileStream << cmVS10EscapeXML(name) << "</TargetName>\n"; std::string ext = @@ -2260,10 +2294,10 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions() // A single "." appears to be treated as an empty extension. ext = "."; } - this->WritePlatformConfigTag("TargetExt", *config, 2); + this->WritePlatformConfigTag("TargetExt", config, 2); *this->BuildFileStream << cmVS10EscapeXML(ext) << "</TargetExt>\n"; - this->OutputLinkIncremental(*config); + this->OutputLinkIncremental(config); } } this->WriteString("</PropertyGroup>\n", 1); @@ -2311,12 +2345,22 @@ void cmVisualStudio10TargetGenerator::OutputLinkIncremental( } } +std::vector<std::string> cmVisualStudio10TargetGenerator::GetIncludes( + std::string const& config, std::string const& lang) const +{ + std::vector<std::string> includes; + this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget, + lang, config); + for (std::string& i : includes) { + ConvertToWindowsSlash(i); + } + return includes; +} + bool cmVisualStudio10TargetGenerator::ComputeClOptions() { - for (std::vector<std::string>::const_iterator i = - this->Configurations.begin(); - i != this->Configurations.end(); ++i) { - if (!this->ComputeClOptions(*i)) { + for (std::string const& i : this->Configurations) { + if (!this->ComputeClOptions(i)) { return false; } } @@ -2359,20 +2403,21 @@ 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; } } } + this->LangForClCompile = langForClCompile; if (!langForClCompile.empty()) { std::string baseFlagVar = "CMAKE_"; baseFlagVar += langForClCompile; @@ -2408,7 +2453,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( clOptions.FixExceptionHandlingDefault(); clOptions.AddFlag("PrecompiledHeader", "NotUsing"); std::string asmLocation = configName + "/"; - clOptions.AddFlag("AssemblerListingLocation", asmLocation.c_str()); + clOptions.AddFlag("AssemblerListingLocation", asmLocation); } } clOptions.Parse(flags.c_str()); @@ -2416,8 +2461,10 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( std::vector<std::string> targetDefines; switch (this->ProjectType) { case vcxproj: - this->GeneratorTarget->GetCompileDefinitions(targetDefines, configName, - "CXX"); + if (!langForClCompile.empty()) { + this->GeneratorTarget->GetCompileDefinitions(targetDefines, configName, + langForClCompile); + } break; case csproj: this->GeneratorTarget->GetCompileDefinitions(targetDefines, configName, @@ -2425,6 +2472,13 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( break; } clOptions.AddDefines(targetDefines); + + // Get includes for this target + if (!this->LangForClCompile.empty()) { + clOptions.AddIncludes( + this->GetIncludes(configName, this->LangForClCompile)); + } + if (this->MSTools) { clOptions.SetVerboseMakefile( this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE")); @@ -2476,12 +2530,12 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( } } - this->ClOptions[configName] = pOptions.release(); + this->ClOptions[configName] = std::move(pOptions); return true; } void cmVisualStudio10TargetGenerator::WriteClOptions( - std::string const& configName, std::vector<std::string> const& includes) + std::string const& configName) { Options& clOptions = *(this->ClOptions[configName]); if (this->ProjectType == csproj) { @@ -2489,12 +2543,11 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( } this->WriteString("<ClCompile>\n", 2); clOptions.PrependInheritedString("AdditionalOptions"); - clOptions.AppendFlag("AdditionalIncludeDirectories", includes); - clOptions.AppendFlag("AdditionalIncludeDirectories", - "%(AdditionalIncludeDirectories)"); + clOptions.OutputAdditionalIncludeDirectories( + *this->BuildFileStream, " ", "\n", this->LangForClCompile); clOptions.OutputFlagMap(*this->BuildFileStream, " "); clOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ", - "\n", "CXX"); + "\n", this->LangForClCompile); if (this->NsightTegra) { if (const char* processMax = @@ -2518,17 +2571,18 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( } // If not in debug mode, write the DebugInformationFormat field - // without value so PDBs don't get generated uselessly. + // without value so PDBs don't get generated uselessly. Each tag + // goes on its own line because Visual Studio corrects it this + // way when saving the project after CMake generates it. if (!clOptions.IsDebug()) { - this->WriteString("<DebugInformationFormat>" - "</DebugInformationFormat>\n", - 3); + this->WriteString("<DebugInformationFormat>\n", 3); + this->WriteString("</DebugInformationFormat>\n", 3); } // Specify the compiler program database file if configured. std::string pdb = this->GeneratorTarget->GetCompilePDBPath(configName); if (!pdb.empty()) { - this->ConvertToWindowsSlash(pdb); + ConvertToWindowsSlash(pdb); this->WriteString("<ProgramDataBaseFileName>", 3); *this->BuildFileStream << cmVS10EscapeXML(pdb) << "</ProgramDataBaseFileName>\n"; @@ -2540,10 +2594,8 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( bool cmVisualStudio10TargetGenerator::ComputeRcOptions() { - for (std::vector<std::string>::const_iterator i = - this->Configurations.begin(); - i != this->Configurations.end(); ++i) { - if (!this->ComputeRcOptions(*i)) { + for (std::string const& i : this->Configurations) { + if (!this->ComputeRcOptions(i)) { return false; } } @@ -2572,12 +2624,15 @@ bool cmVisualStudio10TargetGenerator::ComputeRcOptions( Options& clOptions = *(this->ClOptions[configName]); rcOptions.AddDefines(clOptions.GetDefines()); - this->RcOptions[configName] = pOptions.release(); + // Get includes for this target + rcOptions.AddIncludes(this->GetIncludes(configName, "RC")); + + this->RcOptions[configName] = std::move(pOptions); return true; } void cmVisualStudio10TargetGenerator::WriteRCOptions( - std::string const& configName, std::vector<std::string> const& includes) + std::string const& configName) { if (!this->MSTools) { return; @@ -2587,9 +2642,8 @@ void cmVisualStudio10TargetGenerator::WriteRCOptions( Options& rcOptions = *(this->RcOptions[configName]); rcOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ", "\n", "RC"); - rcOptions.AppendFlag("AdditionalIncludeDirectories", includes); - rcOptions.AppendFlag("AdditionalIncludeDirectories", - "%(AdditionalIncludeDirectories)"); + rcOptions.OutputAdditionalIncludeDirectories(*this->BuildFileStream, + " ", "\n", "RC"); rcOptions.PrependInheritedString("AdditionalOptions"); rcOptions.OutputFlagMap(*this->BuildFileStream, " "); @@ -2601,10 +2655,8 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions() if (!this->GlobalGenerator->IsCudaEnabled()) { return true; } - for (std::vector<std::string>::const_iterator i = - this->Configurations.begin(); - i != this->Configurations.end(); ++i) { - if (!this->ComputeCudaOptions(*i)) { + for (std::string const& i : this->Configurations) { + if (!this->ComputeCudaOptions(i)) { return false; } } @@ -2638,6 +2690,18 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions( cudaOptions.Parse(defineFlags.c_str()); cudaOptions.ParseFinish(); + // If we haven't explicitly enabled GPU debug information + // explicitly disable it + if (!cudaOptions.HasFlag("GPUDebugInfo")) { + cudaOptions.AddFlag("GPUDebugInfo", "false"); + } + + // The extension on object libraries the CUDA gives isn't + // consistent with how MSVC generates object libraries for C+, so set + // the default to not have any extension + cudaOptions.AddFlag("CompileOut", "$(IntDir)%(Filename).obj"); + + bool notPtx = true; if (this->GeneratorTarget->GetPropertyAsBool("CUDA_SEPARABLE_COMPILATION")) { cudaOptions.AddFlag("GenerateRelocatableDeviceCode", "true"); } else if (this->GeneratorTarget->GetPropertyAsBool( @@ -2646,6 +2710,16 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions( // We drop the %(Extension) component as CMake expects all PTX files // to not have the source file extension at all cudaOptions.AddFlag("CompileOut", "$(IntDir)%(Filename).ptx"); + notPtx = false; + } + + if (notPtx && + cmSystemTools::VersionCompareGreaterEq( + "8.0", this->GlobalGenerator->GetPlatformToolsetCudaString())) { + // Explicitly state that we want this file to be treated as a + // CUDA file no matter what the file extensions is + // This is only needed for < CUDA 9 + cudaOptions.AppendFlagString("AdditionalOptions", "-x cu"); } // CUDA automatically passes the proper '--machine' flag to nvcc @@ -2688,12 +2762,15 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions( cudaOptions.AddDefine(exportMacro); } - this->CudaOptions[configName] = pOptions.release(); + // Get includes for this target + cudaOptions.AddIncludes(this->GetIncludes(configName, "CUDA")); + + this->CudaOptions[configName] = std::move(pOptions); return true; } void cmVisualStudio10TargetGenerator::WriteCudaOptions( - std::string const& configName, std::vector<std::string> const& includes) + std::string const& configName) { if (!this->MSTools || !this->GlobalGenerator->IsCudaEnabled()) { return; @@ -2701,8 +2778,8 @@ void cmVisualStudio10TargetGenerator::WriteCudaOptions( this->WriteString("<CudaCompile>\n", 2); Options& cudaOptions = *(this->CudaOptions[configName]); - cudaOptions.AppendFlag("Include", includes); - cudaOptions.AppendFlag("Include", "%(Include)"); + cudaOptions.OutputAdditionalIncludeDirectories(*this->BuildFileStream, + " ", "\n", "CUDA"); cudaOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ", "\n", "CUDA"); cudaOptions.PrependInheritedString("AdditionalOptions"); @@ -2716,10 +2793,8 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions() if (!this->GlobalGenerator->IsCudaEnabled()) { return true; } - for (std::vector<std::string>::const_iterator i = - this->Configurations.begin(); - i != this->Configurations.end(); ++i) { - if (!this->ComputeCudaLinkOptions(*i)) { + for (std::string const& i : this->Configurations) { + if (!this->ComputeCudaLinkOptions(i)) { return false; } } @@ -2761,7 +2836,7 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions( "-Wno-deprecated-gpu-targets"); } - this->CudaLinkOptions[configName] = pOptions.release(); + this->CudaLinkOptions[configName] = std::move(pOptions); return true; } @@ -2787,10 +2862,8 @@ bool cmVisualStudio10TargetGenerator::ComputeMasmOptions() if (!this->GlobalGenerator->IsMasmEnabled()) { return true; } - for (std::vector<std::string>::const_iterator i = - this->Configurations.begin(); - i != this->Configurations.end(); ++i) { - if (!this->ComputeMasmOptions(*i)) { + for (std::string const& i : this->Configurations) { + if (!this->ComputeMasmOptions(i)) { return false; } } @@ -2814,12 +2887,16 @@ bool cmVisualStudio10TargetGenerator::ComputeMasmOptions( std::string(this->Makefile->GetSafeDefinition(configFlagsVar)); masmOptions.Parse(flags.c_str()); - this->MasmOptions[configName] = pOptions.release(); + + // Get includes for this target + masmOptions.AddIncludes(this->GetIncludes(configName, "ASM_MASM")); + + this->MasmOptions[configName] = std::move(pOptions); return true; } void cmVisualStudio10TargetGenerator::WriteMasmOptions( - std::string const& configName, std::vector<std::string> const& includes) + std::string const& configName) { if (!this->MSTools || !this->GlobalGenerator->IsMasmEnabled()) { return; @@ -2832,8 +2909,8 @@ void cmVisualStudio10TargetGenerator::WriteMasmOptions( "\n", "ASM_MASM"); Options& masmOptions = *(this->MasmOptions[configName]); - masmOptions.AppendFlag("IncludePaths", includes); - masmOptions.AppendFlag("IncludePaths", "%(IncludePaths)"); + masmOptions.OutputAdditionalIncludeDirectories(*this->BuildFileStream, + " ", "\n", "ASM_MASM"); masmOptions.PrependInheritedString("AdditionalOptions"); masmOptions.OutputFlagMap(*this->BuildFileStream, " "); @@ -2845,10 +2922,8 @@ bool cmVisualStudio10TargetGenerator::ComputeNasmOptions() if (!this->GlobalGenerator->IsNasmEnabled()) { return true; } - for (std::vector<std::string>::const_iterator i = - this->Configurations.begin(); - i != this->Configurations.end(); ++i) { - if (!this->ComputeNasmOptions(*i)) { + for (std::string const& i : this->Configurations) { + if (!this->ComputeNasmOptions(i)) { return false; } } @@ -2873,25 +2948,27 @@ bool cmVisualStudio10TargetGenerator::ComputeNasmOptions( std::string(" ") + std::string(this->Makefile->GetSafeDefinition(configFlagsVar)); nasmOptions.Parse(flags.c_str()); - this->NasmOptions[configName] = pOptions.release(); + + // Get includes for this target + nasmOptions.AddIncludes(this->GetIncludes(configName, "ASM_NASM")); + + this->NasmOptions[configName] = std::move(pOptions); return true; } void cmVisualStudio10TargetGenerator::WriteNasmOptions( - std::string const& configName, std::vector<std::string> includes) + std::string const& configName) { if (!this->GlobalGenerator->IsNasmEnabled()) { return; } this->WriteString("<NASM>\n", 2); + std::vector<std::string> includes = + this->GetIncludes(configName, "ASM_NASM"); Options& nasmOptions = *(this->NasmOptions[configName]); - for (size_t i = 0; i < includes.size(); i++) { - includes[i] += "\\"; - } - - nasmOptions.AppendFlag("IncludePaths", includes); - nasmOptions.AppendFlag("IncludePaths", "%(IncludePaths)"); + nasmOptions.OutputAdditionalIncludeDirectories(*this->BuildFileStream, + " ", "\n", "ASM_NASM"); nasmOptions.OutputFlagMap(*this->BuildFileStream, " "); nasmOptions.PrependInheritedString("AdditionalOptions"); nasmOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ", @@ -2955,11 +3032,9 @@ void cmVisualStudio10TargetGenerator::WriteManifestOptions( if (!manifest_srcs.empty()) { this->WriteString("<Manifest>\n", 2); this->WriteString("<AdditionalManifestFiles>", 3); - for (std::vector<cmSourceFile const*>::const_iterator mi = - manifest_srcs.begin(); - mi != manifest_srcs.end(); ++mi) { - std::string m = this->ConvertPath((*mi)->GetFullPath(), false); - this->ConvertToWindowsSlash(m); + for (cmSourceFile const* mi : manifest_srcs) { + std::string m = this->ConvertPath(mi->GetFullPath(), false); + ConvertToWindowsSlash(m); (*this->BuildFileStream) << m << ";"; } (*this->BuildFileStream) << "</AdditionalManifestFiles>\n"; @@ -2976,12 +3051,10 @@ void cmVisualStudio10TargetGenerator::WriteAntBuildOptions( { std::vector<cmSourceFile const*> extraSources; this->GeneratorTarget->GetExtraSources(extraSources, ""); - for (std::vector<cmSourceFile const*>::const_iterator si = - extraSources.begin(); - si != extraSources.end(); ++si) { + for (cmSourceFile const* si : extraSources) { if ("androidmanifest.xml" == - cmSystemTools::LowerCase((*si)->GetLocation().GetName())) { - rootDir = (*si)->GetLocation().GetDirectory(); + cmSystemTools::LowerCase(si->GetLocation().GetName())) { + rootDir = si->GetLocation().GetDirectory(); break; } } @@ -2992,7 +3065,7 @@ void cmVisualStudio10TargetGenerator::WriteAntBuildOptions( std::string antBuildPath = rootDir; this->WriteString("<AntBuild>\n", 2); this->WriteString("<AntBuildPath>", 3); - this->ConvertToWindowsSlash(antBuildPath); + ConvertToWindowsSlash(antBuildPath); (*this->BuildFileStream) << cmVS10EscapeXML(antBuildPath) << "</AntBuildPath>\n"; } @@ -3079,7 +3152,7 @@ void cmVisualStudio10TargetGenerator::WriteAntBuildOptions( { std::string manifest_xml = rootDir + "/AndroidManifest.xml"; - this->ConvertToWindowsSlash(manifest_xml); + ConvertToWindowsSlash(manifest_xml); this->WriteString("<AndroidManifestLocation>", 3); (*this->BuildFileStream) << cmVS10EscapeXML(manifest_xml) << "</AndroidManifestLocation>\n"; @@ -3100,10 +3173,8 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions() if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE || this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY || this->GeneratorTarget->GetType() == cmStateEnums::MODULE_LIBRARY) { - for (std::vector<std::string>::const_iterator i = - this->Configurations.begin(); - i != this->Configurations.end(); ++i) { - if (!this->ComputeLinkOptions(*i)) { + for (std::string const& i : this->Configurations) { + if (!this->ComputeLinkOptions(i)) { return false; } } @@ -3200,19 +3271,17 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions( linkOptions.AddFlag("AdditionalDependencies", libVec); // Populate TargetsFileAndConfigsVec - for (std::vector<std::string>::iterator ti = vsTargetVec.begin(); - ti != vsTargetVec.end(); ++ti) { - this->AddTargetsFileAndConfigPair(*ti, config); + for (std::string const& ti : vsTargetVec) { + this->AddTargetsFileAndConfigPair(ti, config); } std::vector<std::string> const& ldirs = cli.GetDirectories(); std::vector<std::string> linkDirs; - for (std::vector<std::string>::const_iterator d = ldirs.begin(); - d != ldirs.end(); ++d) { + for (std::string const& d : ldirs) { // first just full path - linkDirs.push_back(*d); + linkDirs.push_back(d); // next path with configuration type Debug, Release, etc - linkDirs.push_back(*d + "/$(Configuration)"); + linkDirs.push_back(d + "/$(Configuration)"); } linkDirs.push_back("%(AdditionalLibraryDirectories)"); linkOptions.AddFlag("AdditionalLibraryDirectories", linkDirs); @@ -3275,8 +3344,8 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions( imLib += "/"; imLib += targetNameImport; - linkOptions.AddFlag("ImportLibrary", imLib.c_str()); - linkOptions.AddFlag("ProgramDataBaseFile", pdb.c_str()); + linkOptions.AddFlag("ImportLibrary", imLib); + linkOptions.AddFlag("ProgramDataBaseFile", pdb); // A Windows Runtime component uses internal .NET metadata, // so does not have an import library. @@ -3297,7 +3366,7 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions( linkOptions.AppendFlag("IgnoreSpecificDefaultLibraries", "ole32.lib"); } } else if (this->NsightTegra) { - linkOptions.AddFlag("SoName", targetNameSO.c_str()); + linkOptions.AddFlag("SoName", targetNameSO); } linkOptions.Parse(flags.c_str()); @@ -3325,17 +3394,15 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions( } } - this->LinkOptions[config] = pOptions.release(); + this->LinkOptions[config] = std::move(pOptions); return true; } bool cmVisualStudio10TargetGenerator::ComputeLibOptions() { if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) { - for (std::vector<std::string>::const_iterator i = - this->Configurations.begin(); - i != this->Configurations.end(); ++i) { - if (!this->ComputeLibOptions(*i)) { + for (std::string const& i : this->Configurations) { + if (!this->ComputeLibOptions(i)) { return false; } } @@ -3360,11 +3427,11 @@ bool cmVisualStudio10TargetGenerator::ComputeLibOptions( const ItemVector& libs = cli.GetItems(); std::string currentBinDir = this->LocalGenerator->GetCurrentBinaryDirectory(); - for (ItemVector::const_iterator l = libs.begin(); l != libs.end(); ++l) { - if (l->IsPath && cmVS10IsTargetsFile(l->Value)) { + for (cmComputeLinkInformation::Item const& l : libs) { + if (l.IsPath && cmVS10IsTargetsFile(l.Value)) { std::string path = - this->LocalGenerator->ConvertToRelativePath(currentBinDir, l->Value); - this->ConvertToWindowsSlash(path); + this->LocalGenerator->ConvertToRelativePath(currentBinDir, l.Value); + ConvertToWindowsSlash(path); this->AddTargetsFileAndConfigPair(path, config); } } @@ -3406,19 +3473,19 @@ void cmVisualStudio10TargetGenerator::AddLibraries( ItemVector const& libs = cli.GetItems(); std::string currentBinDir = this->LocalGenerator->GetCurrentBinaryDirectory(); - for (ItemVector::const_iterator l = libs.begin(); l != libs.end(); ++l) { - if (l->IsPath) { + for (cmComputeLinkInformation::Item const& l : libs) { + if (l.IsPath) { std::string path = - this->LocalGenerator->ConvertToRelativePath(currentBinDir, l->Value); - this->ConvertToWindowsSlash(path); - if (cmVS10IsTargetsFile(l->Value)) { + this->LocalGenerator->ConvertToRelativePath(currentBinDir, l.Value); + ConvertToWindowsSlash(path); + if (cmVS10IsTargetsFile(l.Value)) { vsTargetVec.push_back(path); } else { libVec.push_back(path); } - } else if (!l->Target || - l->Target->GetType() != cmStateEnums::INTERFACE_LIBRARY) { - libVec.push_back(l->Value); + } else if (!l.Target || + l.Target->GetType() != cmStateEnums::INTERFACE_LIBRARY) { + libVec.push_back(l.Value); } } } @@ -3426,13 +3493,11 @@ void cmVisualStudio10TargetGenerator::AddLibraries( void cmVisualStudio10TargetGenerator::AddTargetsFileAndConfigPair( std::string const& targetsFile, std::string const& config) { - for (std::vector<TargetsFileAndConfigs>::iterator i = - this->TargetsFileAndConfigsVec.begin(); - i != this->TargetsFileAndConfigsVec.end(); ++i) { - if (cmSystemTools::ComparePath(targetsFile, i->File)) { - if (std::find(i->Configs.begin(), i->Configs.end(), config) == - i->Configs.end()) { - i->Configs.push_back(config); + for (TargetsFileAndConfigs& i : this->TargetsFileAndConfigsVec) { + if (cmSystemTools::ComparePath(targetsFile, i.File)) { + if (std::find(i.Configs.begin(), i.Configs.end(), config) == + i.Configs.end()) { + i.Configs.push_back(config); } return; } @@ -3444,7 +3509,7 @@ void cmVisualStudio10TargetGenerator::AddTargetsFileAndConfigPair( } void cmVisualStudio10TargetGenerator::WriteMidlOptions( - std::string const& /*config*/, std::vector<std::string> const& includes) + std::string const& configName) { if (!this->MSTools) { return; @@ -3470,9 +3535,10 @@ void cmVisualStudio10TargetGenerator::WriteMidlOptions( // on the CMake side? this->WriteString("<Midl>\n", 2); this->WriteString("<AdditionalIncludeDirectories>", 3); - for (std::vector<std::string>::const_iterator i = includes.begin(); - i != includes.end(); ++i) { - *this->BuildFileStream << cmVS10EscapeXML(*i) << ";"; + std::vector<std::string> const includes = + this->GetIncludes(configName, "MIDL"); + for (std::string const& i : includes) { + *this->BuildFileStream << cmVS10EscapeXML(i) << ";"; } this->WriteString("%(AdditionalIncludeDirectories)" "</AdditionalIncludeDirectories>\n", @@ -3494,44 +3560,35 @@ void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups() if (this->ProjectType == csproj) { return; } - for (std::vector<std::string>::const_iterator i = - this->Configurations.begin(); - i != this->Configurations.end(); ++i) { - std::vector<std::string> includes; - this->LocalGenerator->GetIncludeDirectories( - includes, this->GeneratorTarget, "C", *i); - for (std::vector<std::string>::iterator ii = includes.begin(); - ii != includes.end(); ++ii) { - this->ConvertToWindowsSlash(*ii); - } - this->WritePlatformConfigTag("ItemDefinitionGroup", *i, 1); + for (const auto& i : this->Configurations) { + this->WritePlatformConfigTag("ItemDefinitionGroup", i, 1); *this->BuildFileStream << "\n"; // output cl compile flags <ClCompile></ClCompile> if (this->GeneratorTarget->GetType() <= cmStateEnums::OBJECT_LIBRARY) { - this->WriteClOptions(*i, includes); + this->WriteClOptions(i); // output rc compile flags <ResourceCompile></ResourceCompile> - this->WriteRCOptions(*i, includes); - this->WriteCudaOptions(*i, includes); - this->WriteMasmOptions(*i, includes); - this->WriteNasmOptions(*i, includes); + this->WriteRCOptions(i); + this->WriteCudaOptions(i); + this->WriteMasmOptions(i); + this->WriteNasmOptions(i); } // output midl flags <Midl></Midl> - this->WriteMidlOptions(*i, includes); + this->WriteMidlOptions(i); // write events if (this->ProjectType != csproj) { - this->WriteEvents(*i); + this->WriteEvents(i); } // output link flags <Link></Link> - this->WriteLinkOptions(*i); - this->WriteCudaLinkOptions(*i); + this->WriteLinkOptions(i); + this->WriteCudaLinkOptions(i); // output lib flags <Lib></Lib> - this->WriteLibOptions(*i); + this->WriteLibOptions(i); // output manifest flags <Manifest></Manifest> - this->WriteManifestOptions(*i); + this->WriteManifestOptions(i); if (this->NsightTegra && this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE && this->GeneratorTarget->GetPropertyAsBool("ANDROID_GUI")) { - this->WriteAntBuildOptions(*i); + this->WriteAntBuildOptions(i); } this->WriteString("</ItemDefinitionGroup>\n", 1); } @@ -3574,9 +3631,8 @@ void cmVisualStudio10TargetGenerator::WriteEvent( std::string script; const char* pre = ""; std::string comment; - for (std::vector<cmCustomCommand>::const_iterator i = commands.begin(); - i != commands.end(); ++i) { - cmCustomCommandGenerator ccg(*i, configName, this->LocalGenerator); + for (cmCustomCommand const& i : commands) { + cmCustomCommandGenerator ccg(i, configName, this->LocalGenerator); if (!ccg.HasOnlyEmptyCommandLines()) { comment += pre; comment += lg->ConstructComment(ccg); @@ -3616,9 +3672,8 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences() OrderedTargetDependSet; OrderedTargetDependSet depends(unordered, CMAKE_CHECK_BUILD_SYSTEM_TARGET); this->WriteString("<ItemGroup>\n", 1); - for (OrderedTargetDependSet::const_iterator i = depends.begin(); - i != depends.end(); ++i) { - cmGeneratorTarget const* dt = *i; + for (cmTargetDepend const& i : depends) { + cmGeneratorTarget const* dt = i; if (dt->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } @@ -3639,9 +3694,9 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences() path = lg->GetCurrentBinaryDirectory(); path += "/"; path += dt->GetName(); - path += computeProjectFileExtension(dt); + path += computeProjectFileExtension(dt, *this->Configurations.begin()); } - this->ConvertToWindowsSlash(path); + ConvertToWindowsSlash(path); (*this->BuildFileStream) << cmVS10EscapeXML(path) << "\">\n"; this->WriteString("<Project>", 3); (*this->BuildFileStream) << "{" << this->GlobalGenerator->GetGUID(name) @@ -3713,10 +3768,9 @@ void cmVisualStudio10TargetGenerator::WriteSDKReferences() cmSystemTools::ExpandListArgument(vsSDKReferences, sdkReferences); this->WriteString("<ItemGroup>\n", 1); hasWrittenItemGroup = true; - for (std::vector<std::string>::iterator ri = sdkReferences.begin(); - ri != sdkReferences.end(); ++ri) { + for (std::string const& ri : sdkReferences) { this->WriteString("<SDKReference Include=\"", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(*ri) << "\"/>\n"; + (*this->BuildFileStream) << cmVS10EscapeXML(ri) << "\"/>\n"; } } @@ -3771,11 +3825,9 @@ void cmVisualStudio10TargetGenerator::WriteWinRTPackageCertificateKeyFile() std::string pfxFile; std::vector<cmSourceFile const*> certificates; this->GeneratorTarget->GetCertificates(certificates, ""); - for (std::vector<cmSourceFile const*>::const_iterator si = - certificates.begin(); - si != certificates.end(); ++si) { - pfxFile = this->ConvertPath((*si)->GetFullPath(), false); - this->ConvertToWindowsSlash(pfxFile); + for (cmSourceFile const* si : certificates) { + pfxFile = this->ConvertPath(si->GetFullPath(), false); + ConvertToWindowsSlash(pfxFile); break; } @@ -3785,7 +3837,7 @@ void cmVisualStudio10TargetGenerator::WriteWinRTPackageCertificateKeyFile() // Move the manifest to a project directory to avoid clashes std::string artifactDir = this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); - this->ConvertToWindowsSlash(artifactDir); + ConvertToWindowsSlash(artifactDir); this->WriteString("<PropertyGroup>\n", 1); this->WriteString("<AppxPackageArtifactsDir>", 2); (*this->BuildFileStream) << cmVS10EscapeXML(artifactDir) @@ -3793,7 +3845,7 @@ void cmVisualStudio10TargetGenerator::WriteWinRTPackageCertificateKeyFile() this->WriteString("<ProjectPriFullPath>", 2); std::string resourcePriFile = this->DefaultArtifactDir + "/resources.pri"; - this->ConvertToWindowsSlash(resourcePriFile); + ConvertToWindowsSlash(resourcePriFile); (*this->BuildFileStream) << resourcePriFile << "</ProjectPriFullPath>\n"; // If we are missing files and we don't have a certificate and @@ -3804,7 +3856,7 @@ void cmVisualStudio10TargetGenerator::WriteWinRTPackageCertificateKeyFile() pfxFile = this->DefaultArtifactDir + "/Windows_TemporaryKey.pfx"; cmSystemTools::CopyAFile(templateFolder + "/Windows_TemporaryKey.pfx", pfxFile, false); - this->ConvertToWindowsSlash(pfxFile); + ConvertToWindowsSlash(pfxFile); this->AddedFiles.push_back(pfxFile); } @@ -3986,12 +4038,10 @@ void cmVisualStudio10TargetGenerator::VerifyNecessaryFiles() std::vector<cmSourceFile const*> extraSources; this->GeneratorTarget->GetExtraSources(extraSources, ""); bool foundManifest = false; - for (std::vector<cmSourceFile const*>::const_iterator si = - extraSources.begin(); - si != extraSources.end(); ++si) { + for (cmSourceFile const* si : extraSources) { // Need to do a lowercase comparison on the filename if ("wmappmanifest.xml" == - cmSystemTools::LowerCase((*si)->GetLocation().GetName())) { + cmSystemTools::LowerCase(si->GetLocation().GetName())) { foundManifest = true; break; } @@ -4050,7 +4100,7 @@ void cmVisualStudio10TargetGenerator::WriteMissingFilesWP80() std::string("/WMAppManifest.xml"); std::string artifactDir = this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); - this->ConvertToWindowsSlash(artifactDir); + ConvertToWindowsSlash(artifactDir); std::string artifactDirXML = cmVS10EscapeXML(artifactDir); std::string targetNameXML = cmVS10EscapeXML(this->GeneratorTarget->GetName()); @@ -4097,7 +4147,7 @@ void cmVisualStudio10TargetGenerator::WriteMissingFilesWP80() /* clang-format on */ std::string sourceFile = this->ConvertPath(manifestFile, false); - this->ConvertToWindowsSlash(sourceFile); + ConvertToWindowsSlash(sourceFile); this->WriteString("<Xml Include=\"", 2); (*this->BuildFileStream) << cmVS10EscapeXML(sourceFile) << "\">\n"; this->WriteString("<SubType>Designer</SubType>\n", 3); @@ -4107,14 +4157,14 @@ void cmVisualStudio10TargetGenerator::WriteMissingFilesWP80() std::string smallLogo = this->DefaultArtifactDir + "/SmallLogo.png"; cmSystemTools::CopyAFile(templateFolder + "/SmallLogo.png", smallLogo, false); - this->ConvertToWindowsSlash(smallLogo); + ConvertToWindowsSlash(smallLogo); this->WriteString("<Image Include=\"", 2); (*this->BuildFileStream) << cmVS10EscapeXML(smallLogo) << "\" />\n"; this->AddedFiles.push_back(smallLogo); std::string logo = this->DefaultArtifactDir + "/Logo.png"; cmSystemTools::CopyAFile(templateFolder + "/Logo.png", logo, false); - this->ConvertToWindowsSlash(logo); + ConvertToWindowsSlash(logo); this->WriteString("<Image Include=\"", 2); (*this->BuildFileStream) << cmVS10EscapeXML(logo) << "\" />\n"; this->AddedFiles.push_back(logo); @@ -4123,7 +4173,7 @@ void cmVisualStudio10TargetGenerator::WriteMissingFilesWP80() this->DefaultArtifactDir + "/ApplicationIcon.png"; cmSystemTools::CopyAFile(templateFolder + "/ApplicationIcon.png", applicationIcon, false); - this->ConvertToWindowsSlash(applicationIcon); + ConvertToWindowsSlash(applicationIcon); this->WriteString("<Image Include=\"", 2); (*this->BuildFileStream) << cmVS10EscapeXML(applicationIcon) << "\" />\n"; this->AddedFiles.push_back(applicationIcon); @@ -4135,7 +4185,7 @@ void cmVisualStudio10TargetGenerator::WriteMissingFilesWP81() this->DefaultArtifactDir + "/package.appxManifest"; std::string artifactDir = this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); - this->ConvertToWindowsSlash(artifactDir); + ConvertToWindowsSlash(artifactDir); std::string artifactDirXML = cmVS10EscapeXML(artifactDir); std::string targetNameXML = cmVS10EscapeXML(this->GeneratorTarget->GetName()); @@ -4198,7 +4248,7 @@ void cmVisualStudio10TargetGenerator::WriteMissingFilesWS80() this->DefaultArtifactDir + "/package.appxManifest"; std::string artifactDir = this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); - this->ConvertToWindowsSlash(artifactDir); + ConvertToWindowsSlash(artifactDir); std::string artifactDirXML = cmVS10EscapeXML(artifactDir); std::string targetNameXML = cmVS10EscapeXML(this->GeneratorTarget->GetName()); @@ -4253,7 +4303,7 @@ void cmVisualStudio10TargetGenerator::WriteMissingFilesWS81() this->DefaultArtifactDir + "/package.appxManifest"; std::string artifactDir = this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); - this->ConvertToWindowsSlash(artifactDir); + ConvertToWindowsSlash(artifactDir); std::string artifactDirXML = cmVS10EscapeXML(artifactDir); std::string targetNameXML = cmVS10EscapeXML(this->GeneratorTarget->GetName()); @@ -4313,7 +4363,7 @@ void cmVisualStudio10TargetGenerator::WriteMissingFilesWS10_0() this->DefaultArtifactDir + "/package.appxManifest"; std::string artifactDir = this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); - this->ConvertToWindowsSlash(artifactDir); + ConvertToWindowsSlash(artifactDir); std::string artifactDirXML = cmVS10EscapeXML(artifactDir); std::string targetNameXML = cmVS10EscapeXML(this->GeneratorTarget->GetName()); @@ -4375,7 +4425,7 @@ void cmVisualStudio10TargetGenerator::WriteCommonMissingFiles( cmSystemTools::GetCMakeRoot() + "/Templates/Windows"; std::string sourceFile = this->ConvertPath(manifestFile, false); - this->ConvertToWindowsSlash(sourceFile); + ConvertToWindowsSlash(sourceFile); this->WriteString("<AppxManifest Include=\"", 2); (*this->BuildFileStream) << cmVS10EscapeXML(sourceFile) << "\">\n"; this->WriteString("<SubType>Designer</SubType>\n", 3); @@ -4385,7 +4435,7 @@ void cmVisualStudio10TargetGenerator::WriteCommonMissingFiles( std::string smallLogo = this->DefaultArtifactDir + "/SmallLogo.png"; cmSystemTools::CopyAFile(templateFolder + "/SmallLogo.png", smallLogo, false); - this->ConvertToWindowsSlash(smallLogo); + ConvertToWindowsSlash(smallLogo); this->WriteString("<Image Include=\"", 2); (*this->BuildFileStream) << cmVS10EscapeXML(smallLogo) << "\" />\n"; this->AddedFiles.push_back(smallLogo); @@ -4393,14 +4443,14 @@ void cmVisualStudio10TargetGenerator::WriteCommonMissingFiles( std::string smallLogo44 = this->DefaultArtifactDir + "/SmallLogo44x44.png"; cmSystemTools::CopyAFile(templateFolder + "/SmallLogo44x44.png", smallLogo44, false); - this->ConvertToWindowsSlash(smallLogo44); + ConvertToWindowsSlash(smallLogo44); this->WriteString("<Image Include=\"", 2); (*this->BuildFileStream) << cmVS10EscapeXML(smallLogo44) << "\" />\n"; this->AddedFiles.push_back(smallLogo44); std::string logo = this->DefaultArtifactDir + "/Logo.png"; cmSystemTools::CopyAFile(templateFolder + "/Logo.png", logo, false); - this->ConvertToWindowsSlash(logo); + ConvertToWindowsSlash(logo); this->WriteString("<Image Include=\"", 2); (*this->BuildFileStream) << cmVS10EscapeXML(logo) << "\" />\n"; this->AddedFiles.push_back(logo); @@ -4408,7 +4458,7 @@ void cmVisualStudio10TargetGenerator::WriteCommonMissingFiles( std::string storeLogo = this->DefaultArtifactDir + "/StoreLogo.png"; cmSystemTools::CopyAFile(templateFolder + "/StoreLogo.png", storeLogo, false); - this->ConvertToWindowsSlash(storeLogo); + ConvertToWindowsSlash(storeLogo); this->WriteString("<Image Include=\"", 2); (*this->BuildFileStream) << cmVS10EscapeXML(storeLogo) << "\" />\n"; this->AddedFiles.push_back(storeLogo); @@ -4416,14 +4466,14 @@ void cmVisualStudio10TargetGenerator::WriteCommonMissingFiles( std::string splashScreen = this->DefaultArtifactDir + "/SplashScreen.png"; cmSystemTools::CopyAFile(templateFolder + "/SplashScreen.png", splashScreen, false); - this->ConvertToWindowsSlash(splashScreen); + ConvertToWindowsSlash(splashScreen); this->WriteString("<Image Include=\"", 2); (*this->BuildFileStream) << cmVS10EscapeXML(splashScreen) << "\" />\n"; this->AddedFiles.push_back(splashScreen); // This file has already been added to the build so don't copy it std::string keyFile = this->DefaultArtifactDir + "/Windows_TemporaryKey.pfx"; - this->ConvertToWindowsSlash(keyFile); + ConvertToWindowsSlash(keyFile); this->WriteString("<None Include=\"", 2); (*this->BuildFileStream) << cmVS10EscapeXML(keyFile) << "\" />\n"; } @@ -4453,13 +4503,12 @@ void cmVisualStudio10TargetGenerator::GetCSharpSourceProperties( { if (this->ProjectType == csproj) { const cmPropertyMap& props = sf->GetProperties(); - for (cmPropertyMap::const_iterator p = props.begin(); p != props.end(); - ++p) { + for (auto const& p : props) { static const std::string propNamePrefix = "VS_CSHARP_"; - if (p->first.find(propNamePrefix) == 0) { - std::string tagName = p->first.substr(propNamePrefix.length()); + if (p.first.find(propNamePrefix) == 0) { + std::string tagName = p.first.substr(propNamePrefix.length()); if (!tagName.empty()) { - const std::string val = props.GetPropertyValue(p->first); + const std::string val = props.GetPropertyValue(p.first); if (!val.empty()) { tags[tagName] = val; } else { @@ -4475,11 +4524,10 @@ void cmVisualStudio10TargetGenerator::WriteCSharpSourceProperties( const std::map<std::string, std::string>& tags) { if (!tags.empty()) { - for (std::map<std::string, std::string>::const_iterator i = tags.begin(); - i != tags.end(); ++i) { + for (const auto& i : tags) { this->WriteString("<", 3); - (*this->BuildFileStream) << i->first << ">" << cmVS10EscapeXML(i->second) - << "</" << i->first << ">\n"; + (*this->BuildFileStream) << i.first << ">" << cmVS10EscapeXML(i.second) + << "</" << i.first << ">\n"; } } } @@ -4496,7 +4544,7 @@ void cmVisualStudio10TargetGenerator::GetCSharpSourceLink( if (const char* l = sf->GetProperty("VS_CSHARP_Link")) { link = l; } - this->ConvertToWindowsSlash(link); + ConvertToWindowsSlash(link); } } } @@ -4507,7 +4555,7 @@ std::string cmVisualStudio10TargetGenerator::GetCMakeFilePath( // Always search in the standard modules location. std::string path = cmSystemTools::GetCMakeRoot() + "/"; path += relativeFilePath; - this->ConvertToWindowsSlash(path); + ConvertToWindowsSlash(path); return path; } diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index fb24f1a..33d4fb7 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -7,6 +7,7 @@ #include <iosfwd> #include <map> +#include <memory> #include <set> #include <string> #include <vector> @@ -24,6 +25,8 @@ class cmVisualStudioGeneratorOptions; class cmVisualStudio10TargetGenerator { + CM_DISABLE_COPY(cmVisualStudio10TargetGenerator) + public: cmVisualStudio10TargetGenerator(cmGeneratorTarget* target, cmGlobalVisualStudio10Generator* gg); @@ -51,7 +54,6 @@ private: }; std::string ConvertPath(std::string const& path, bool forceRelative); - static void ConvertToWindowsSlash(std::string& s); void WriteString(const char* line, int indentLevel); void WriteProjectConfigurations(); void WriteProjectConfigurationValues(); @@ -90,18 +92,18 @@ private: void WriteTargetSpecificReferences(); void WriteTargetsFileReferences(); + std::vector<std::string> GetIncludes(std::string const& config, + std::string const& lang) const; + bool ComputeClOptions(); bool ComputeClOptions(std::string const& configName); - void WriteClOptions(std::string const& config, - std::vector<std::string> const& includes); + void WriteClOptions(std::string const& config); bool ComputeRcOptions(); bool ComputeRcOptions(std::string const& config); - void WriteRCOptions(std::string const& config, - std::vector<std::string> const& includes); + void WriteRCOptions(std::string const& config); bool ComputeCudaOptions(); bool ComputeCudaOptions(std::string const& config); - void WriteCudaOptions(std::string const& config, - std::vector<std::string> const& includes); + void WriteCudaOptions(std::string const& config); bool ComputeCudaLinkOptions(); bool ComputeCudaLinkOptions(std::string const& config); @@ -109,20 +111,17 @@ private: bool ComputeMasmOptions(); bool ComputeMasmOptions(std::string const& config); - void WriteMasmOptions(std::string const& config, - std::vector<std::string> const& includes); + void WriteMasmOptions(std::string const& config); bool ComputeNasmOptions(); bool ComputeNasmOptions(std::string const& config); - void WriteNasmOptions(std::string const& config, - std::vector<std::string> includes); + void WriteNasmOptions(std::string const& config); bool ComputeLinkOptions(); bool ComputeLinkOptions(std::string const& config); bool ComputeLibOptions(); bool ComputeLibOptions(std::string const& config); void WriteLinkOptions(std::string const& config); - void WriteMidlOptions(std::string const& config, - std::vector<std::string> const& includes); + void WriteMidlOptions(std::string const& config); void WriteAntBuildOptions(std::string const& config); void OutputLinkIncremental(std::string const& configName); void WriteCustomRule(cmSourceFile const* source, @@ -172,7 +171,7 @@ private: private: typedef cmVisualStudioGeneratorOptions Options; - typedef std::map<std::string, Options*> OptionsMap; + typedef std::map<std::string, std::unique_ptr<Options>> OptionsMap; OptionsMap ClOptions; OptionsMap RcOptions; OptionsMap CudaOptions; @@ -180,6 +179,7 @@ private: OptionsMap MasmOptions; OptionsMap NasmOptions; OptionsMap LinkOptions; + std::string LangForClCompile; std::string PathToProjectFile; std::string ProjectFileExtension; enum VsProjectType diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx index b1686be..ccbff83 100644 --- a/Source/cmVisualStudioGeneratorOptions.cxx +++ b/Source/cmVisualStudioGeneratorOptions.cxx @@ -29,23 +29,8 @@ static std::string cmVisualStudioGeneratorOptionsEscapeForXML(std::string ret) cmVisualStudioGeneratorOptions::cmVisualStudioGeneratorOptions( cmLocalVisualStudioGenerator* lg, Tool tool, cmVisualStudio10TargetGenerator* g) - : cmIDEOptions() - , LocalGenerator(lg) - , Version(lg->GetVersion()) - , CurrentTool(tool) - , TargetGenerator(g) + : cmVisualStudioGeneratorOptions(lg, tool, nullptr, nullptr, g) { - // Preprocessor definitions are not allowed for linker tools. - this->AllowDefine = (tool != Linker); - - // Slash options are allowed for VS. - this->AllowSlash = true; - - this->FortranRuntimeDebug = false; - this->FortranRuntimeDLL = false; - this->FortranRuntimeMT = false; - - this->UnknownFlagField = "AdditionalOptions"; } cmVisualStudioGeneratorOptions::cmVisualStudioGeneratorOptions( @@ -64,6 +49,9 @@ cmVisualStudioGeneratorOptions::cmVisualStudioGeneratorOptions( // Preprocessor definitions are not allowed for linker tools. this->AllowDefine = (tool != Linker); + // include directories are not allowed for linker tools. + this->AllowInclude = (tool != Linker); + // Slash options are allowed for VS. this->AllowSlash = true; @@ -239,26 +227,38 @@ void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration() // It translates to -arch=<virtual> -code=<real>. cmSystemTools::ReplaceString(arch_name, "sm_", "compute_"); } - for (std::vector<std::string>::iterator ci = codes.begin(); - ci != codes.end(); ++ci) { - std::string entry = arch_name + "," + *ci; + for (auto const& c : codes) { + std::string entry = arch_name + "," + c; result.push_back(entry); } } - // Now add entries for the -gencode=<arch>,<code> pairs. - for (std::vector<std::string>::iterator ei = gencode.begin(); - ei != gencode.end(); ++ei) { - std::string entry = *ei; + // Now add entries for the following signatures: + // -gencode=<arch>,<code> + // -gencode=<arch>,[<code1>,<code2>] + // -gencode=<arch>,"<code1>,<code2>" + for (auto const& e : gencode) { + std::string entry = e; cmSystemTools::ReplaceString(entry, "arch=", ""); cmSystemTools::ReplaceString(entry, "code=", ""); - result.push_back(entry); + cmSystemTools::ReplaceString(entry, "[", ""); + cmSystemTools::ReplaceString(entry, "]", ""); + cmSystemTools::ReplaceString(entry, "\"", ""); + + std::vector<std::string> codes = cmSystemTools::tokenize(entry, ","); + if (codes.size() >= 2) { + auto gencode_arch = cm::cbegin(codes); + for (auto ci = gencode_arch + 1; ci != cm::cend(codes); ++ci) { + std::string code_entry = *gencode_arch + "," + *ci; + result.push_back(code_entry); + } + } } } void cmVisualStudioGeneratorOptions::FixManifestUACFlags() { - static const char* ENABLE_UAC = "EnableUAC"; + static std::string const ENABLE_UAC = "EnableUAC"; if (!HasFlag(ENABLE_UAC)) { return; } @@ -304,8 +304,7 @@ void cmVisualStudioGeneratorOptions::FixManifestUACFlags() continue; } - AddFlag(uacMap[keyValue[0]].c_str(), - uacExecuteLevelMap[keyValue[1]].c_str()); + AddFlag(uacMap[keyValue[0]], uacExecuteLevelMap[keyValue[1]]); continue; } @@ -314,11 +313,11 @@ void cmVisualStudioGeneratorOptions::FixManifestUACFlags() // unknown uiAccess value continue; } - AddFlag(uacMap[keyValue[0]].c_str(), keyValue[1].c_str()); + AddFlag(uacMap[keyValue[0]], keyValue[1]); continue; } - // unknwon sub option + // unknown sub option } AddFlag(ENABLE_UAC, "true"); @@ -500,6 +499,69 @@ void cmVisualStudioGeneratorOptions::OutputPreprocessorDefinitions( } } +void cmVisualStudioGeneratorOptions::OutputAdditionalIncludeDirectories( + std::ostream& fout, const char* prefix, const char* suffix, + const std::string& lang) +{ + if (this->Includes.empty()) { + return; + } + + const char* tag = "AdditionalIncludeDirectories"; + if (lang == "CUDA") { + tag = "Include"; + } else if (lang == "ASM_MASM" || lang == "ASM_NASM") { + tag = "IncludePaths"; + } + + if (this->Version >= cmGlobalVisualStudioGenerator::VS10) { + // if there are configuration specific flags, then + // use the configuration specific tag for PreprocessorDefinitions + if (!this->Configuration.empty()) { + fout << prefix; + this->TargetGenerator->WritePlatformConfigTag( + tag, this->Configuration.c_str(), 0, 0, 0, &fout); + } else { + fout << prefix << "<" << tag << ">"; + } + } else { + fout << prefix << tag << "=\""; + } + + const char* sep = ""; + for (std::string include : this->Includes) { + // first convert all of the slashes + std::string::size_type pos = 0; + while ((pos = include.find('/', pos)) != std::string::npos) { + include[pos] = '\\'; + pos++; + } + + if (lang == "ASM_NASM") { + include += "\\"; + } + + // Escape this include for the IDE. + fout << sep << (this->Version >= cmGlobalVisualStudioGenerator::VS10 + ? cmVisualStudio10GeneratorOptionsEscapeForXML(include) + : cmVisualStudioGeneratorOptionsEscapeForXML(include)); + sep = ";"; + + if (lang == "Fortran") { + include += "/$(ConfigurationName)"; + fout << sep << (this->Version >= cmGlobalVisualStudioGenerator::VS10 + ? cmVisualStudio10GeneratorOptionsEscapeForXML(include) + : cmVisualStudioGeneratorOptionsEscapeForXML(include)); + } + } + + if (this->Version >= cmGlobalVisualStudioGenerator::VS10) { + fout << sep << "%(" << tag << ")</" << tag << ">" << suffix; + } else { + fout << "\"" << suffix; + } +} + void cmVisualStudioGeneratorOptions::OutputFlagMap(std::ostream& fout, const char* indent) { diff --git a/Source/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h index 7c08a2c..2dffe9b 100644 --- a/Source/cmVisualStudioGeneratorOptions.h +++ b/Source/cmVisualStudioGeneratorOptions.h @@ -86,6 +86,10 @@ public: void OutputPreprocessorDefinitions(std::ostream& fout, const char* prefix, const char* suffix, const std::string& lang); + void OutputAdditionalIncludeDirectories(std::ostream& fout, + const char* prefix, + const char* suffix, + const std::string& lang); void OutputFlagMap(std::ostream& fout, const char* indent); void SetConfiguration(const char* config); diff --git a/Source/cmWriteFileCommand.cxx b/Source/cmWriteFileCommand.cxx index fc5fd21..3464a1b 100644 --- a/Source/cmWriteFileCommand.cxx +++ b/Source/cmWriteFileCommand.cxx @@ -33,7 +33,7 @@ bool cmWriteFileCommand::InitialPass(std::vector<std::string> const& args, } } - if (!this->Makefile->CanIWriteThisFile(fileName.c_str())) { + if (!this->Makefile->CanIWriteThisFile(fileName)) { std::string e = "attempted to write a file: " + fileName + " into a source directory."; this->SetError(e); @@ -42,7 +42,7 @@ bool cmWriteFileCommand::InitialPass(std::vector<std::string> const& args, } std::string dir = cmSystemTools::GetFilenamePath(fileName); - cmSystemTools::MakeDirectory(dir.c_str()); + cmSystemTools::MakeDirectory(dir); mode_t mode = 0; 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..7bae21e 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 arbitrary 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..84e6a5c --- /dev/null +++ b/Source/cm_thread.hxx @@ -0,0 +1,44 @@ +/* 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 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(); } +}; +} +#endif diff --git a/Source/cmake.cxx b/Source/cmake.cxx index fd7151f..5620723 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -7,6 +7,7 @@ #include "cmDocumentation.h" #include "cmDocumentationEntry.h" #include "cmDocumentationFormatter.h" +#include "cmDuration.h" #include "cmExternalMakefileProjectGenerator.h" #include "cmFileTimeComparison.h" #include "cmGeneratorTarget.h" @@ -34,14 +35,6 @@ #include <unordered_map> #endif -// only build kdevelop generator on non-windows platforms -// when not bootstrapping cmake -#if !defined(_WIN32) -#if defined(CMAKE_BUILD_WITH_CMAKE) -#define CMAKE_USE_KDEVELOP -#endif -#endif - #if defined(CMAKE_BUILD_WITH_CMAKE) #define CMAKE_USE_ECLIPSE #endif @@ -87,10 +80,6 @@ #include "cmExtraKateGenerator.h" #include "cmExtraSublimeTextGenerator.h" -#ifdef CMAKE_USE_KDEVELOP -#include "cmGlobalKdevelopGenerator.h" -#endif - #ifdef CMAKE_USE_ECLIPSE #include "cmExtraEclipseCDT4Generator.h" #endif @@ -110,6 +99,7 @@ #include "cmsys/RegularExpression.hxx" #include <algorithm> #include <iostream> +#include <iterator> #include <memory> // IWYU pragma: keep #include <sstream> #include <stdio.h> @@ -195,10 +185,16 @@ cmake::cmake(Role role) this->SourceFileExtensions.push_back("cc"); this->SourceFileExtensions.push_back("cpp"); this->SourceFileExtensions.push_back("cxx"); + this->SourceFileExtensions.push_back("cu"); this->SourceFileExtensions.push_back("m"); 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 +203,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() @@ -486,7 +487,7 @@ void cmake::ReadListFile(const std::vector<std::string>& args, if (this->GetWorkingMode() != NORMAL_MODE) { std::string file(cmSystemTools::CollapseFullPath(path)); cmSystemTools::ConvertToUnixSlashes(file); - mf.SetScriptModeFile(file.c_str()); + mf.SetScriptModeFile(file); mf.SetArgcArgv(args); } @@ -744,8 +745,13 @@ void cmake::SetArgs(const std::vector<std::string>& args, } cmGlobalGenerator* gen = this->CreateGlobalGenerator(value); if (!gen) { + const char* kdevError = nullptr; + if (value.find("KDevelop3", 0) != std::string::npos) { + kdevError = "\nThe KDevelop3 generator is not supported anymore."; + } + cmSystemTools::Error("Could not create named generator ", - value.c_str()); + value.c_str(), kdevError); this->PrintGeneratorList(); } else { this->SetGlobalGenerator(gen); @@ -777,10 +783,10 @@ void cmake::SetDirectoriesFromFile(const char* arg) cacheFile += "/CMakeCache.txt"; std::string listFile = path; listFile += "/CMakeLists.txt"; - if (cmSystemTools::FileExists(cacheFile.c_str())) { + if (cmSystemTools::FileExists(cacheFile)) { cachePath = path; } - if (cmSystemTools::FileExists(listFile.c_str())) { + if (cmSystemTools::FileExists(listFile)) { listPath = path; } } else if (cmSystemTools::FileExists(arg)) { @@ -863,7 +869,7 @@ int cmake::AddCMakePaths() "Path to cpack program executable.", cmStateEnums::INTERNAL); #endif if (!cmSystemTools::FileExists( - (cmSystemTools::GetCMakeRoot() + "/Modules/CMake.cmake").c_str())) { + (cmSystemTools::GetCMakeRoot() + "/Modules/CMake.cmake"))) { // couldn't find modules cmSystemTools::Error( "Could not find CMAKE_ROOT !!!\n" @@ -890,9 +896,6 @@ void cmake::AddDefaultExtraGenerators() this->ExtraGenerators.push_back(cmExtraEclipseCDT4Generator::GetFactory()); #endif -#ifdef CMAKE_USE_KDEVELOP - this->ExtraGenerators.push_back(cmGlobalKdevelopGenerator::GetFactory()); -#endif #endif } @@ -910,7 +913,7 @@ void cmake::GetRegisteredGenerators( info.name = name; info.baseName = name; info.isAlias = false; - generators.push_back(info); + generators.push_back(std::move(info)); } } @@ -926,7 +929,7 @@ void cmake::GetRegisteredGenerators( info.supportsPlatform = false; info.supportsToolset = false; info.isAlias = false; - generators.push_back(info); + generators.push_back(std::move(info)); } for (std::string const& a : eg->Aliases) { GeneratorInfo info; @@ -938,7 +941,7 @@ void cmake::GetRegisteredGenerators( info.supportsPlatform = false; info.supportsToolset = false; info.isAlias = true; - generators.push_back(info); + generators.push_back(std::move(info)); } } } @@ -1000,7 +1003,7 @@ void cmake::SetHomeDirectory(const std::string& dir) } } -const char* cmake::GetHomeDirectory() const +std::string const& cmake::GetHomeDirectory() const { return this->State->GetSourceDirectory(); } @@ -1013,7 +1016,7 @@ void cmake::SetHomeOutputDirectory(const std::string& dir) } } -const char* cmake::GetHomeOutputDirectory() const +std::string const& cmake::GetHomeOutputDirectory() const { return this->State->GetBinaryDirectory(); } @@ -1024,11 +1027,11 @@ std::string cmake::FindCacheFile(const std::string& binaryDir) cmSystemTools::ConvertToUnixSlashes(cachePath); std::string cacheFile = cachePath; cacheFile += "/CMakeCache.txt"; - if (!cmSystemTools::FileExists(cacheFile.c_str())) { + if (!cmSystemTools::FileExists(cacheFile)) { // search in parent directories for cache std::string cmakeFiles = cachePath; cmakeFiles += "/CMakeFiles"; - if (cmSystemTools::FileExists(cmakeFiles.c_str())) { + if (cmSystemTools::FileExists(cmakeFiles)) { std::string cachePathFound = cmSystemTools::FileExistsInParentDirectories("CMakeCache.txt", cachePath.c_str(), "/"); @@ -1084,7 +1087,7 @@ int cmake::DoPreConfigureChecks() // Make sure the Source directory contains a CMakeLists.txt file. std::string srcList = this->GetHomeDirectory(); srcList += "/CMakeLists.txt"; - if (!cmSystemTools::FileExists(srcList.c_str())) { + if (!cmSystemTools::FileExists(srcList)) { std::ostringstream err; if (cmSystemTools::FileIsDirectory(this->GetHomeDirectory())) { err << "The source directory \"" << this->GetHomeDirectory() @@ -1165,7 +1168,7 @@ int cmake::HandleDeleteCacheVariables(const std::string& var) save.help = help; } } - saved.push_back(save); + saved.push_back(std::move(save)); } // remove the cache @@ -1269,7 +1272,7 @@ int cmake::ActualConfigure() } if (!res) { this->AddCacheEntry( - "CMAKE_HOME_DIRECTORY", this->GetHomeDirectory(), + "CMAKE_HOME_DIRECTORY", this->GetHomeDirectory().c_str(), "Source directory with the top level CMakeLists.txt file for this " "project", cmStateEnums::INTERNAL); @@ -1326,6 +1329,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 +1475,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, @@ -1487,14 +1509,14 @@ void cmake::PreLoadCMakeFiles() std::string pre_load = this->GetHomeDirectory(); if (!pre_load.empty()) { pre_load += "/PreLoad.cmake"; - if (cmSystemTools::FileExists(pre_load.c_str())) { + if (cmSystemTools::FileExists(pre_load)) { this->ReadListFile(args, pre_load.c_str()); } } pre_load = this->GetHomeOutputDirectory(); if (!pre_load.empty()) { pre_load += "/PreLoad.cmake"; - if (cmSystemTools::FileExists(pre_load.c_str())) { + if (cmSystemTools::FileExists(pre_load)) { this->ReadListFile(args, pre_load.c_str()); } } @@ -1627,6 +1649,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); @@ -1687,7 +1724,7 @@ int cmake::LoadCache() // if it does exist, but isn't readable then warn the user std::string cacheFile = this->GetHomeOutputDirectory(); cacheFile += "/CMakeCache.txt"; - if (cmSystemTools::FileExists(cacheFile.c_str())) { + if (cmSystemTools::FileExists(cacheFile)) { cmSystemTools::Error( "There is a CMakeCache.txt file for the current binary tree but " "cmake does not have permission to read it. Please check the " @@ -1716,8 +1753,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; @@ -1725,13 +1762,13 @@ bool cmake::LoadCache(const std::string& path, bool internal, bool cmake::SaveCache(const std::string& path) { - bool result = this->State->SaveCache(path); + bool result = this->State->SaveCache(path, this->GetMessenger()); static const char* entries[] = { "CMAKE_CACHE_MAJOR_VERSION", "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; @@ -1771,7 +1808,7 @@ void cmake::GetGeneratorDocumentation(std::vector<cmDocumentationEntry>& v) for (cmGlobalGeneratorFactory* g : this->Generators) { cmDocumentationEntry e; g->GetDocumentation(e); - v.push_back(e); + v.push_back(std::move(e)); } for (cmExternalMakefileProjectGeneratorFactory* eg : this->ExtraGenerators) { const std::string doc = eg->GetDocumentation(); @@ -1782,7 +1819,7 @@ void cmake::GetGeneratorDocumentation(std::vector<cmDocumentationEntry>& v) cmDocumentationEntry e; e.Name = a; e.Brief = doc; - v.push_back(e); + v.push_back(std::move(e)); } // Full names: @@ -1793,7 +1830,7 @@ void cmake::GetGeneratorDocumentation(std::vector<cmDocumentationEntry>& v) e.Name = cmExternalMakefileProjectGenerator::CreateFullGeneratorName(g, name); e.Brief = doc; - v.push_back(e); + v.push_back(std::move(e)); } } } @@ -1854,7 +1891,7 @@ int cmake::CheckBuildSystem() } // If the file provided does not exist, we have to rerun. - if (!cmSystemTools::FileExists(this->CheckBuildSystemArgument.c_str())) { + if (!cmSystemTools::FileExists(this->CheckBuildSystemArgument)) { if (verbose) { std::ostringstream msg; msg << "Re-run cmake missing file: " << this->CheckBuildSystemArgument @@ -1908,8 +1945,7 @@ int cmake::CheckBuildSystem() cmSystemTools::ExpandListArgument(productStr, products); } for (std::string const& p : products) { - if (!(cmSystemTools::FileExists(p.c_str()) || - cmSystemTools::FileIsSymlink(p))) { + if (!(cmSystemTools::FileExists(p) || cmSystemTools::FileIsSymlink(p))) { if (verbose) { std::ostringstream msg; msg << "Re-run cmake, missing byproduct: " << p << "\n"; @@ -2107,7 +2143,7 @@ int cmake::GetSystemInformation(std::vector<std::string>& args) std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); std::string destPath = cwd + "/__cmake_systeminformation"; cmSystemTools::RemoveADirectory(destPath); - if (!cmSystemTools::MakeDirectory(destPath.c_str())) { + if (!cmSystemTools::MakeDirectory(destPath)) { std::cerr << "Error: --system-information must be run from a " "writable directory!\n"; return 1; @@ -2139,7 +2175,7 @@ int cmake::GetSystemInformation(std::vector<std::string>& args) } // no option assume it is the output file else { - if (!cmSystemTools::FileIsFullPath(arg.c_str())) { + if (!cmSystemTools::FileIsFullPath(arg)) { resultFile = cwd; resultFile += "/"; } @@ -2176,9 +2212,7 @@ int cmake::GetSystemInformation(std::vector<std::string>& args) std::vector<std::string> args2; args2.push_back(args[0]); args2.push_back(destPath); - std::string resultArg = "-DRESULT_FILE="; - resultArg += resultFile; - args2.push_back(resultArg); + args2.push_back("-DRESULT_FILE=" + resultFile); int res = this->Run(args2, false); if (res != 0) { @@ -2360,6 +2394,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 = @@ -2386,7 +2428,7 @@ int cmake::Build(const std::string& dir, const std::string& target, cmGlobalVisualStudio8Generator::GetGenerateStampList(); // Note that the stampList file only exists for VS generators. - if (cmSystemTools::FileExists(stampList.c_str()) && + if (cmSystemTools::FileExists(stampList) && !cmakeCheckStampList(stampList.c_str(), false)) { // Correctly initialize the home (=source) and home output (=binary) @@ -2421,8 +2463,51 @@ int cmake::Build(const std::string& dir, const std::string& target, #endif return gen->Build("", dir, projName, target, output, "", config, clean, - false, verbose, 0, cmSystemTools::OUTPUT_PASSTHROUGH, - nativeOptions); + false, verbose, cmDuration::zero(), + cmSystemTools::OUTPUT_PASSTHROUGH, 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) diff --git a/Source/cmake.h b/Source/cmake.h index b31b6f5..1ac549b 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" @@ -141,9 +142,9 @@ public: * path-to-source cmake was run with. */ void SetHomeDirectory(const std::string& dir); - const char* GetHomeDirectory() const; + std::string const& GetHomeDirectory() const; void SetHomeOutputDirectory(const std::string& dir); - const char* GetHomeOutputDirectory() const; + std::string const& GetHomeOutputDirectory() const; //@} /** @@ -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..b185a1b 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -16,10 +16,6 @@ #include "cmDynamicLoader.h" #endif -#ifdef _WIN32 -#include <fcntl.h> /* _O_TEXT */ -#include <stdlib.h> /* _set_fmode, _fmode */ -#endif #include "cm_uv.h" #include "cmsys/Encoding.hxx" @@ -66,6 +62,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 +97,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) { @@ -168,24 +166,16 @@ int main(int ac, char const* const* av) ac = args.argc(); av = args.argv(); -#if defined(_WIN32) - // Perform libuv one-time initialization now, and then un-do its - // global _fmode setting so that using libuv does not change the - // default file text/binary mode. See libuv issue 840. - uv_loop_close(uv_default_loop()); -#ifdef _MSC_VER - _set_fmode(_O_TEXT); -#else - _fmode = _O_TEXT; -#endif -#endif - cmSystemTools::EnableMSVCDebugHook(); + cmSystemTools::InitializeLibUV(); cmSystemTools::FindCMakeResources(av[0]); if (ac > 1) { 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 +413,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/cmakexbuild.cxx b/Source/cmakexbuild.cxx index 20ead47..2951945 100644 --- a/Source/cmakexbuild.cxx +++ b/Source/cmakexbuild.cxx @@ -8,6 +8,7 @@ #include <string> #include <vector> +#include "cmDuration.h" #include "cmSystemTools.h" // This is a wrapper program for xcodebuild @@ -27,7 +28,8 @@ int RunXCode(std::vector<const char*>& argv, bool& hitbug) std::vector<char> out; std::vector<char> err; std::string line; - int pipe = cmSystemTools::WaitForLine(cp, line, 100.0, out, err); + int pipe = + cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out, err); while (pipe != cmsysProcess_Pipe_None) { if (line.find("/bin/sh: bad interpreter: Text file busy") != std::string::npos) { @@ -45,7 +47,8 @@ int RunXCode(std::vector<const char*>& argv, bool& hitbug) std::cout << line << "\n"; } } - pipe = cmSystemTools::WaitForLine(cp, line, 100, out, err); + pipe = cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out, + err); } cmsysProcess_WaitForExit(cp, nullptr); if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) { diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 69339b4..0988c3c 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -3,10 +3,12 @@ #include "cmcmd.h" #include "cmAlgorithms.h" +#include "cmDuration.h" #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 +36,7 @@ #include "cmsys/Terminal.h" #include <algorithm> #include <iostream> +#include <iterator> #include <memory> // IWYU pragma: keep #include <sstream> #include <stdio.h> @@ -101,7 +104,7 @@ void CMakeCommandUsage(const char* program) << " sleep <number>... - sleep for given number of seconds\n" << " tar [cxt][vf][zjJ] file.tar [file/dir1 file/dir2 ...]\n" << " - create or extract a tar or zip archive\n" - << " time command [args...] - run command and return elapsed time\n" + << " time command [args...] - run command and display elapsed time\n" << " touch file - touch a file.\n" << " touch_nocreate file - touch a file but do not create it.\n" #if defined(_WIN32) && !defined(__CYGWIN__) @@ -268,10 +271,12 @@ static int HandleCppLint(const std::string& runCmd, << "\n"; return 1; } - + std::cerr << "Warning: cpplint diagnostics:\n"; // Output the output from cpplint to stderr std::cerr << stdOut; - return ret; + // always return 0 so the build can continue as cpplint returns non-zero + // for any warning + return 0; } static int HandleCppCheck(const std::string& runCmd, @@ -371,8 +376,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 +407,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; @@ -636,7 +641,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args) // If error occurs we want to continue copying next files. bool return_value = false; for (std::string::size_type cc = 2; cc < args.size(); cc++) { - if (!cmSystemTools::MakeDirectory(args[cc].c_str())) { + if (!cmSystemTools::MakeDirectory(args[cc])) { std::cerr << "Error creating directory \"" << args[cc] << "\".\n"; return_value = true; } @@ -663,7 +668,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args) // Complain if the file could not be removed, still exists, // and the -f option was not given. if (!cmSystemTools::RemoveFile(args[cc]) && !force && - cmSystemTools::FileExists(args[cc].c_str())) { + cmSystemTools::FileExists(args[cc])) { return 1; } } @@ -784,7 +789,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args) // Command to change directory and run a program. if (args[1] == "chdir" && args.size() >= 4) { std::string const& directory = args[2]; - if (!cmSystemTools::FileExists(directory.c_str())) { + if (!cmSystemTools::FileExists(directory)) { cmSystemTools::Error("Directory does not exist for chdir command: ", args[2].c_str()); return 1; @@ -793,10 +798,9 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args) std::string command = cmWrap('"', cmMakeRange(args).advance(3), '"', " "); int retval = 0; - int timeout = 0; if (cmSystemTools::RunSingleCommand( command.c_str(), nullptr, nullptr, &retval, directory.c_str(), - cmSystemTools::OUTPUT_PASSTHROUGH, timeout)) { + cmSystemTools::OUTPUT_PASSTHROUGH, cmDuration::zero())) { return retval; } @@ -822,7 +826,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args) count = atoi(args[3].c_str()); } if (count) { - cmSystemTools::MakeDirectory(dirName.c_str()); + cmSystemTools::MakeDirectory(dirName); // write the count into the directory std::string fName = dirName; fName += "/count.txt"; @@ -991,11 +995,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 +1037,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: ", @@ -1224,9 +1237,12 @@ int cmcmd::HashSumFile(std::vector<std::string>& args, cmCryptoHash::Algo algo) int cmcmd::SymlinkLibrary(std::vector<std::string>& args) { int result = 0; - std::string const& realName = args[2]; - std::string const& soName = args[3]; - std::string const& name = args[4]; + std::string realName = args[2]; + std::string soName = args[3]; + std::string name = args[4]; + cmSystemTools::ConvertToUnixSlashes(realName); + cmSystemTools::ConvertToUnixSlashes(soName); + cmSystemTools::ConvertToUnixSlashes(name); if (soName != realName) { if (!cmcmd::SymlinkInternal(realName, soName)) { cmSystemTools::ReportLastSystemError("cmake_symlink_library"); @@ -1258,8 +1274,7 @@ int cmcmd::SymlinkExecutable(std::vector<std::string>& args) bool cmcmd::SymlinkInternal(std::string const& file, std::string const& link) { - if (cmSystemTools::FileExists(link.c_str()) || - cmSystemTools::FileIsSymlink(link)) { + if (cmSystemTools::FileExists(link) || cmSystemTools::FileIsSymlink(link)) { cmSystemTools::RemoveFile(link); } #if defined(_WIN32) && !defined(__CYGWIN__) diff --git a/Source/ctest.cxx b/Source/ctest.cxx index f6466fa..0a6d1d2 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", @@ -139,6 +137,7 @@ int main(int argc, char const* const* argv) cmSystemTools::DoNotInheritStdPipes(); cmSystemTools::EnableMSVCDebugHook(); + cmSystemTools::InitializeLibUV(); cmSystemTools::FindCMakeResources(argv[0]); // Dispatch 'ctest --launch' mode directly. diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt index 21568bb..4fc176b 100644 --- a/Source/kwsys/CMakeLists.txt +++ b/Source/kwsys/CMakeLists.txt @@ -83,7 +83,9 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6.3 FATAL_ERROR) FOREACH(p + CMP0022 # CMake 2.8, Define link interface - required by android_mk export CMP0025 # CMake 3.0, Compiler id for Apple Clang is now AppleClang. + CMP0042 # CMake 3.0, MACOSX_RPATH is enabled by default. CMP0048 # CMake 3.0, Let the project command manage version variables. CMP0056 # CMake 3.2, Honor link flags in try_compile() source-file signature. CMP0063 # CMake 3.3, Honor visibility properties for all target types. @@ -445,8 +447,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) @@ -489,6 +496,24 @@ IF(KWSYS_USE_SystemTools) KWSYS_CXX_STAT_HAS_ST_MTIM=${KWSYS_CXX_STAT_HAS_ST_MTIM} KWSYS_CXX_STAT_HAS_ST_MTIMESPEC=${KWSYS_CXX_STAT_HAS_ST_MTIMESPEC} ) + IF(NOT WIN32) + IF(KWSYS_STANDALONE) + OPTION(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES "If true, Windows paths will be supported on Unix as well" ON) + ENDIF() + IF(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES) + SET_PROPERTY(SOURCE SystemTools.cxx testSystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS + KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES + ) + ENDIF() + ENDIF() + + # Disable getpwnam for static linux builds since it depends on shared glibc + GET_PROPERTY(SHARED_LIBS_SUPPORTED GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS) + IF(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT SHARED_LIBS_SUPPORTED) + SET_PROPERTY(SOURCE SystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS + HAVE_GETPWNAM=0 + ) + ENDIF() ENDIF() IF(KWSYS_USE_SystemInformation) @@ -571,7 +596,7 @@ IF(KWSYS_USE_SystemInformation) CHECK_INCLUDE_FILE_CXX("execinfo.h" KWSYS_CXX_HAS_EXECINFOH) IF (KWSYS_CXX_HAS_EXECINFOH) # we have the backtrace header check if it - # can be used with this compiler + # can be used with this compiler SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES ${EXECINFO_LIB}) KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BACKTRACE "Checking whether backtrace works with this C++ compiler" DIRECT) @@ -700,9 +725,13 @@ ENDIF() # selected components. Initialize with required components. SET(KWSYS_CLASSES) SET(KWSYS_H_FILES Configure SharedForward) -SET(KWSYS_HXX_FILES Configure String - hashtable hash_fun hash_map hash_set - ) +SET(KWSYS_HXX_FILES Configure String) + +IF(NOT CMake_SOURCE_DIR) + SET(KWSYS_HXX_FILES ${KWSYS_HXX_FILES} + hashtable hash_fun hash_map hash_set + ) +ENDIF() # Add selected C++ classes. SET(cppclasses @@ -893,7 +922,7 @@ IF(KWSYS_C_SRCS OR KWSYS_CXX_SRCS) # Set up include usage requirement IF(COMMAND TARGET_INCLUDE_DIRECTORIES) TARGET_INCLUDE_DIRECTORIES(${KWSYS_TARGET_INTERFACE} INTERFACE - $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>) + $<BUILD_INTERFACE:${KWSYS_HEADER_ROOT}>) IF(KWSYS_INSTALL_INCLUDE_DIR) TARGET_INCLUDE_DIRECTORIES(${KWSYS_TARGET_INTERFACE} INTERFACE $<INSTALL_INTERFACE:${KWSYS_INSTALL_INCLUDE_DIR}>) @@ -947,7 +976,7 @@ IF(KWSYS_ENABLE_C AND KWSYS_C_SRCS) # Set up include usage requirement IF(COMMAND TARGET_INCLUDE_DIRECTORIES) TARGET_INCLUDE_DIRECTORIES(${KWSYS_TARGET_C_INTERFACE} INTERFACE - $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>) + $<BUILD_INTERFACE:${KWSYS_HEADER_ROOT}>) IF(KWSYS_INSTALL_INCLUDE_DIR) TARGET_INCLUDE_DIRECTORIES(${KWSYS_TARGET_C_INTERFACE} INTERFACE $<INSTALL_INTERFACE:${KWSYS_INSTALL_INCLUDE_DIR}>) @@ -1003,11 +1032,11 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) # C tests SET(KWSYS_C_TESTS - testEncode - testTerminal + testEncode.c + testTerminal.c ) IF(KWSYS_STANDALONE) - SET(KWSYS_C_TESTS ${KWSYS_C_TESTS} testFail) + SET(KWSYS_C_TESTS ${KWSYS_C_TESTS} testFail.c) ENDIF() CREATE_TEST_SOURCELIST( KWSYS_C_TEST_SRCS ${KWSYS_NAMESPACE}TestsC.c @@ -1016,31 +1045,33 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) ADD_EXECUTABLE(${KWSYS_NAMESPACE}TestsC ${KWSYS_C_TEST_SRCS}) SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsC PROPERTY LABELS ${KWSYS_LABELS_EXE}) TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE}TestsC ${KWSYS_TARGET_C_LINK}) - FOREACH(test ${KWSYS_C_TESTS}) + FOREACH(testfile ${KWSYS_C_TESTS}) + get_filename_component(test "${testfile}" NAME_WE) ADD_TEST(kwsys.${test} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestsC ${test} ${KWSYS_TEST_ARGS_${test}}) SET_PROPERTY(TEST kwsys.${test} PROPERTY LABELS ${KWSYS_LABELS_TEST}) ENDFOREACH() # C++ tests - IF(NOT WATCOM) + IF(NOT WATCOM AND NOT CMake_SOURCE_DIR) SET(KWSYS_CXX_TESTS - testHashSTL + testHashSTL.cxx ) ENDIF() SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} - testSystemTools - testCommandLineArguments - testCommandLineArguments1 - testDirectory + testConfigure.cxx + testSystemTools.cxx + testCommandLineArguments.cxx + testCommandLineArguments1.cxx + testDirectory.cxx ) IF(KWSYS_STL_HAS_WSTRING) SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} - testEncoding + testEncoding.cxx ) ENDIF() IF(KWSYS_USE_FStream) SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} - testFStream + testFStream.cxx ) ENDIF() IF(KWSYS_USE_ConsoleBuf) @@ -1052,7 +1083,7 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) SET_PROPERTY(TARGET testConsoleBufChild PROPERTY LABELS ${KWSYS_LABELS_EXE}) TARGET_LINK_LIBRARIES(testConsoleBufChild ${KWSYS_TARGET_LINK}) SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} - testConsoleBuf + testConsoleBuf.cxx ) IF("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "19.0.23506") @@ -1062,10 +1093,10 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE}) ENDIF() IF(KWSYS_USE_SystemInformation) - SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testSystemInformation) + SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testSystemInformation.cxx) ENDIF() IF(KWSYS_USE_DynamicLoader) - SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testDynamicLoader) + SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testDynamicLoader.cxx) # If kwsys contains the DynamicLoader, need extra library ADD_LIBRARY(${KWSYS_NAMESPACE}TestDynload MODULE testDynload.c) SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestDynload PROPERTY LABELS ${KWSYS_LABELS_LIB}) @@ -1124,7 +1155,8 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) -p some junk at the end ) - FOREACH(test ${KWSYS_CXX_TESTS}) + FOREACH(testfile ${KWSYS_CXX_TESTS}) + get_filename_component(test "${testfile}" NAME_WE) ADD_TEST(kwsys.${test} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestsCxx ${test} ${KWSYS_TEST_ARGS_${test}}) SET_PROPERTY(TEST kwsys.${test} PROPERTY LABELS ${KWSYS_LABELS_TEST}) ENDFOREACH() @@ -1142,17 +1174,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..a6387ea 100644 --- a/Source/kwsys/CommandLineArguments.cxx +++ b/Source/kwsys/CommandLineArguments.cxx @@ -68,8 +68,8 @@ class CommandLineArgumentsInternal public: CommandLineArgumentsInternal() { - this->UnknownArgumentCallback = 0; - this->ClientData = 0; + this->UnknownArgumentCallback = KWSYS_NULLPTR; + this->ClientData = KWSYS_NULLPTR; this->LastArgument = 0; } @@ -187,7 +187,7 @@ int CommandLineArguments::Parse() switch (cs->ArgumentType) { case NO_ARGUMENT: // No value - if (!this->PopulateVariable(cs, 0)) { + if (!this->PopulateVariable(cs, KWSYS_NULLPTR)) { return 0; } break; @@ -340,7 +340,7 @@ void CommandLineArguments::AddCallback(const char* argument, s.Callback = callback; s.CallData = call_data; s.VariableType = CommandLineArguments::NO_VARIABLE_TYPE; - s.Variable = 0; + s.Variable = KWSYS_NULLPTR; s.Help = help; this->Internals->Callbacks[argument] = s; @@ -355,8 +355,8 @@ void CommandLineArguments::AddArgument(const char* argument, CommandLineArgumentsCallbackStructure s; s.Argument = argument; s.ArgumentType = type; - s.Callback = 0; - s.CallData = 0; + s.Callback = KWSYS_NULLPTR; + s.CallData = KWSYS_NULLPTR; s.VariableType = vtype; s.Variable = variable; s.Help = help; @@ -427,7 +427,7 @@ const char* CommandLineArguments::GetHelp(const char* arg) CommandLineArguments::Internal::CallbacksMap::iterator it = this->Internals->Callbacks.find(arg); if (it == this->Internals->Callbacks.end()) { - return 0; + return KWSYS_NULLPTR; } // Since several arguments may point to the same argument, find the one this @@ -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); @@ -627,7 +621,7 @@ void CommandLineArguments::PopulateVariable(bool* variable, void CommandLineArguments::PopulateVariable(int* variable, const std::string& value) { - char* res = 0; + char* res = KWSYS_NULLPTR; *variable = static_cast<int>(strtol(value.c_str(), &res, 10)); // if ( res && *res ) // { @@ -638,7 +632,7 @@ void CommandLineArguments::PopulateVariable(int* variable, void CommandLineArguments::PopulateVariable(double* variable, const std::string& value) { - char* res = 0; + char* res = KWSYS_NULLPTR; *variable = strtod(value.c_str(), &res); // if ( res && *res ) // { @@ -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()); } @@ -678,7 +669,7 @@ void CommandLineArguments::PopulateVariable(std::vector<bool>* variable, void CommandLineArguments::PopulateVariable(std::vector<int>* variable, const std::string& value) { - char* res = 0; + char* res = KWSYS_NULLPTR; variable->push_back(static_cast<int>(strtol(value.c_str(), &res, 10))); // if ( res && *res ) // { @@ -689,7 +680,7 @@ void CommandLineArguments::PopulateVariable(std::vector<int>* variable, void CommandLineArguments::PopulateVariable(std::vector<double>* variable, const std::string& value) { - char* res = 0; + char* res = KWSYS_NULLPTR; variable->push_back(strtod(value.c_str(), &res)); // if ( res && *res ) // { 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..05afc7d 100644 --- a/Source/kwsys/Configure.hxx.in +++ b/Source/kwsys/Configure.hxx.in @@ -12,6 +12,37 @@ #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 + +#if __cplusplus >= 201103L +#define @KWSYS_NAMESPACE@_NULLPTR nullptr +#else +#define @KWSYS_NAMESPACE@_NULLPTR 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 +53,8 @@ #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 +#define KWSYS_NULLPTR @KWSYS_NAMESPACE@_NULLPTR #endif #endif diff --git a/Source/kwsys/ConsoleBuf.hxx.in b/Source/kwsys/ConsoleBuf.hxx.in index 46d65a8..cf68146 100644 --- a/Source/kwsys/ConsoleBuf.hxx.in +++ b/Source/kwsys/ConsoleBuf.hxx.in @@ -264,6 +264,7 @@ private: if (m_isConsoleInput) { break; } + @KWSYS_NAMESPACE@_FALLTHROUGH; case FILE_TYPE_PIPE: m_activeInputCodepage = input_pipe_codepage; break; @@ -290,6 +291,7 @@ private: if (m_isConsoleOutput) { break; } + @KWSYS_NAMESPACE@_FALLTHROUGH; case FILE_TYPE_PIPE: m_activeOutputCodepage = output_pipe_codepage; break; diff --git a/Source/kwsys/Directory.cxx b/Source/kwsys/Directory.cxx index 69068aa..a84be11 100644 --- a/Source/kwsys/Directory.cxx +++ b/Source/kwsys/Directory.cxx @@ -48,7 +48,7 @@ unsigned long Directory::GetNumberOfFiles() const const char* Directory::GetFile(unsigned long dindex) const { if (dindex >= this->Internal->Files.size()) { - return 0; + return KWSYS_NULLPTR; } return this->Internal->Files[dindex].c_str(); } diff --git a/Source/kwsys/DynamicLoader.cxx b/Source/kwsys/DynamicLoader.cxx index 1b4596a..9b7d9bf 100644 --- a/Source/kwsys/DynamicLoader.cxx +++ b/Source/kwsys/DynamicLoader.cxx @@ -60,7 +60,7 @@ const char* DynamicLoader::LastError() } // namespace KWSYS_NAMESPACE #elif defined(__hpux) -// Implementation for HPUX machines +// Implementation for HPUX machines #include <dl.h> #include <errno.h> @@ -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/EncodingCXX.cxx b/Source/kwsys/EncodingCXX.cxx index b1e54c9..a1fe040 100644 --- a/Source/kwsys/EncodingCXX.cxx +++ b/Source/kwsys/EncodingCXX.cxx @@ -65,7 +65,7 @@ Encoding::CommandLineArguments::CommandLineArguments(int ac, for (int i = 0; i < ac; i++) { this->argv_[i] = strdup(av[i]); } - this->argv_[ac] = 0; + this->argv_[ac] = KWSYS_NULLPTR; } Encoding::CommandLineArguments::CommandLineArguments(int ac, @@ -75,7 +75,7 @@ Encoding::CommandLineArguments::CommandLineArguments(int ac, for (int i = 0; i < ac; i++) { this->argv_[i] = kwsysEncoding_DupToNarrow(av[i]); } - this->argv_[ac] = 0; + this->argv_[ac] = KWSYS_NULLPTR; } Encoding::CommandLineArguments::~CommandLineArguments() @@ -90,7 +90,7 @@ Encoding::CommandLineArguments::CommandLineArguments( { this->argv_.resize(other.argv_.size()); for (size_t i = 0; i < this->argv_.size(); i++) { - this->argv_[i] = other.argv_[i] ? strdup(other.argv_[i]) : 0; + this->argv_[i] = other.argv_[i] ? strdup(other.argv_[i]) : KWSYS_NULLPTR; } } @@ -105,7 +105,7 @@ Encoding::CommandLineArguments& Encoding::CommandLineArguments::operator=( this->argv_.resize(other.argv_.size()); for (i = 0; i < this->argv_.size(); i++) { - this->argv_[i] = other.argv_[i] ? strdup(other.argv_[i]) : 0; + this->argv_[i] = other.argv_[i] ? strdup(other.argv_[i]) : KWSYS_NULLPTR; } } @@ -193,7 +193,7 @@ std::string Encoding::ToNarrow(const std::wstring& str) std::wstring Encoding::ToWide(const char* cstr) { std::wstring wstr; - size_t length = kwsysEncoding_mbstowcs(0, cstr, 0) + 1; + size_t length = kwsysEncoding_mbstowcs(KWSYS_NULLPTR, cstr, 0) + 1; if (length > 0) { std::vector<wchar_t> wchars(length); if (kwsysEncoding_mbstowcs(&wchars[0], cstr, length) > 0) { @@ -206,7 +206,7 @@ std::wstring Encoding::ToWide(const char* cstr) std::string Encoding::ToNarrow(const wchar_t* wcstr) { std::string str; - size_t length = kwsysEncoding_wcstombs(0, wcstr, 0) + 1; + size_t length = kwsysEncoding_wcstombs(KWSYS_NULLPTR, wcstr, 0) + 1; if (length > 0) { std::vector<char> chars(length); if (kwsysEncoding_wcstombs(&chars[0], wcstr, length) > 0) { diff --git a/Source/kwsys/Glob.cxx b/Source/kwsys/Glob.cxx index d2f0b85..2b6db78 100644 --- a/Source/kwsys/Glob.cxx +++ b/Source/kwsys/Glob.cxx @@ -28,7 +28,7 @@ #include <string.h> namespace KWSYS_NAMESPACE { #if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__) -// On Windows and apple, no difference between lower and upper case +// On Windows and Apple, no difference between lower and upper case #define KWSYS_GLOB_CASE_INDEPENDENT #endif @@ -81,13 +81,13 @@ std::string Glob::PatternToRegex(const std::string& pattern, int c = *i; if (c == '*') { // A '*' (not between brackets) matches any string. - // We modify this to not match slashes since the orignal glob + // We modify this to not match slashes since the original glob // pattern documentation was meant for matching file name // components separated by slashes. regex += "[^/]*"; } else if (c == '?') { // A '?' (not between brackets) matches any single character. - // We modify this to not match slashes since the orignal glob + // We modify this to not match slashes since the original glob // pattern documentation was meant for matching file name // components separated by slashes. regex += "[^/]"; @@ -201,7 +201,7 @@ bool Glob::RecurseDirectory(std::string::size_type start, } #if defined(KWSYS_GLOB_CASE_INDEPENDENT) - // On Windows and apple, no difference between lower and upper case + // On Windows and Apple, no difference between lower and upper case fname = kwsys::SystemTools::LowerCase(fname); #endif @@ -430,7 +430,7 @@ void Glob::SetRelative(const char* dir) const char* Glob::GetRelative() { if (this->Relative.empty()) { - return 0; + return KWSYS_NULLPTR; } return this->Relative.c_str(); } 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..1e80b39 100644 --- a/Source/kwsys/ProcessUNIX.c +++ b/Source/kwsys/ProcessUNIX.c @@ -231,7 +231,7 @@ struct kwsysProcess_s when reaping PIDs or modifying this array to avoid race conditions. */ volatile pid_t* volatile ForkPIDs; - /* Flag for whether the children were terminated by a faild select. */ + /* Flag for whether the children were terminated by a failed select. */ int SelectError; /* The timeout length. */ @@ -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.cxx b/Source/kwsys/RegularExpression.cxx index 26e84e0..78cff1a 100644 --- a/Source/kwsys/RegularExpression.cxx +++ b/Source/kwsys/RegularExpression.cxx @@ -37,18 +37,18 @@ namespace KWSYS_NAMESPACE { RegularExpression::RegularExpression(const RegularExpression& rxp) { if (!rxp.program) { - this->program = 0; + this->program = KWSYS_NULLPTR; return; } int ind; this->progsize = rxp.progsize; // Copy regular expression size this->program = new char[this->progsize]; // Allocate storage - for (ind = this->progsize; ind-- != 0;) // Copy regular expresion + for (ind = this->progsize; ind-- != 0;) // Copy regular expression this->program[ind] = rxp.program[ind]; - this->startp[0] = rxp.startp[0]; // Copy pointers into last - this->endp[0] = rxp.endp[0]; // Successful "find" operation - this->regmust = rxp.regmust; // Copy field - if (rxp.regmust != 0) { + // Copy pointers into last successful "find" operation + this->regmatch = rxp.regmatch; + this->regmust = rxp.regmust; // Copy field + if (rxp.regmust != KWSYS_NULLPTR) { char* dum = rxp.program; ind = 0; while (dum != rxp.regmust) { @@ -69,19 +69,19 @@ RegularExpression& RegularExpression::operator=(const RegularExpression& rxp) return *this; } if (!rxp.program) { - this->program = 0; + this->program = KWSYS_NULLPTR; return *this; } int ind; this->progsize = rxp.progsize; // Copy regular expression size delete[] this->program; this->program = new char[this->progsize]; // Allocate storage - for (ind = this->progsize; ind-- != 0;) // Copy regular expresion + for (ind = this->progsize; ind-- != 0;) // Copy regular expression this->program[ind] = rxp.program[ind]; - this->startp[0] = rxp.startp[0]; // Copy pointers into last - this->endp[0] = rxp.endp[0]; // Successful "find" operation - this->regmust = rxp.regmust; // Copy field - if (rxp.regmust != 0) { + // Copy pointers into last successful "find" operation + this->regmatch = rxp.regmatch; + this->regmust = rxp.regmust; // Copy field + if (rxp.regmust != KWSYS_NULLPTR) { char* dum = rxp.program; ind = 0; while (dum != rxp.regmust) { @@ -123,12 +123,13 @@ bool RegularExpression::deep_equal(const RegularExpression& rxp) const while (ind-- != 0) // Else while still characters if (this->program[ind] != rxp.program[ind]) // If regexp are different return false; // Return failure - return (this->startp[0] == rxp.startp[0] && // Else if same start/end ptrs, - this->endp[0] == rxp.endp[0]); // Return true + // Else if same start/end ptrs, return true + return (this->regmatch.start() == rxp.regmatch.start() && + this->regmatch.end() == rxp.regmatch.end()); } -// The remaining code in this file is derived from the regular expression code -// whose copyright statement appears below. It has been changed to work +// The remaining code in this file is derived from the regular expression code +// whose copyright statement appears below. It has been changed to work // with the class concepts of C++ and COOL. /* @@ -276,31 +277,35 @@ const unsigned char MAGIC = 0234; ///////////////////////////////////////////////////////////////////////// /* - * Global work variables for compile(). + * Read only utility variables. */ -static const char* regparse; // Input-scan pointer. -static int regnpar; // () count. static char regdummy; -static char* regcode; // Code-emit pointer; ®dummy = don't. -static long regsize; // Code size. +static char* const regdummyptr = ®dummy; /* - * Forward declarations for compile()'s friends. + * Utility class for RegularExpression::compile(). */ -// #ifndef static -// #define static static -// #endif -static char* reg(int, int*); -static char* regbranch(int*); -static char* regpiece(int*); -static char* regatom(int*); -static char* regnode(char); +class RegExpCompile +{ +public: + const char* regparse; // Input-scan pointer. + int regnpar; // () count. + char* regcode; // Code-emit pointer; regdummyptr = don't. + long regsize; // Code size. + + char* reg(int, int*); + char* regbranch(int*); + char* regpiece(int*); + char* regatom(int*); + char* regnode(char); + void regc(char); + void reginsert(char, char*); + static void regtail(char*, const char*); + static void regoptail(char*, const char*); +}; + static const char* regnext(const char*); static char* regnext(char*); -static void regc(char); -static void reginsert(char, char*); -static void regtail(char*, const char*); -static void regoptail(char*, const char*); #ifdef STRCSPN static int strcspn(); @@ -330,26 +335,27 @@ bool RegularExpression::compile(const char* exp) size_t len; int flags; - if (exp == 0) { + if (exp == KWSYS_NULLPTR) { // RAISE Error, SYM(RegularExpression), SYM(No_Expr), printf("RegularExpression::compile(): No expression supplied.\n"); return false; } // First pass: determine size, legality. - regparse = exp; - regnpar = 1; - regsize = 0L; - regcode = ®dummy; - regc(static_cast<char>(MAGIC)); - if (!reg(0, &flags)) { + RegExpCompile comp; + comp.regparse = exp; + comp.regnpar = 1; + comp.regsize = 0L; + comp.regcode = regdummyptr; + comp.regc(static_cast<char>(MAGIC)); + if (!comp.reg(0, &flags)) { printf("RegularExpression::compile(): Error in compile.\n"); return false; } - this->startp[0] = this->endp[0] = this->searchstring = 0; + this->regmatch.clear(); // Small enough for pointer-storage convention? - if (regsize >= 32767L) { // Probably could be 65535L. + if (comp.regsize >= 32767L) { // Probably could be 65535L. // RAISE Error, SYM(RegularExpression), SYM(Expr_Too_Big), printf("RegularExpression::compile(): Expression too big.\n"); return false; @@ -357,29 +363,29 @@ bool RegularExpression::compile(const char* exp) // Allocate space. //#ifndef _WIN32 - if (this->program != 0) + if (this->program != KWSYS_NULLPTR) delete[] this->program; //#endif - this->program = new char[regsize]; - this->progsize = static_cast<int>(regsize); + this->program = new char[comp.regsize]; + this->progsize = static_cast<int>(comp.regsize); - if (this->program == 0) { + if (this->program == KWSYS_NULLPTR) { // RAISE Error, SYM(RegularExpression), SYM(Out_Of_Memory), printf("RegularExpression::compile(): Out of memory.\n"); return false; } // Second pass: emit code. - regparse = exp; - regnpar = 1; - regcode = this->program; - regc(static_cast<char>(MAGIC)); - reg(0, &flags); + comp.regparse = exp; + comp.regnpar = 1; + comp.regcode = this->program; + comp.regc(static_cast<char>(MAGIC)); + comp.reg(0, &flags); // Dig out information for optimizations. this->regstart = '\0'; // Worst-case defaults. this->reganch = 0; - this->regmust = 0; + this->regmust = KWSYS_NULLPTR; this->regmlen = 0; scan = this->program + 1; // First BRANCH. if (OP(regnext(scan)) == END) { // Only one top-level choice. @@ -400,9 +406,9 @@ bool RegularExpression::compile(const char* exp) // absence of others. // if (flags & SPSTART) { - longest = 0; + longest = KWSYS_NULLPTR; len = 0; - for (; scan != 0; scan = regnext(scan)) + for (; scan != KWSYS_NULLPTR; scan = regnext(scan)) if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) { longest = OPERAND(scan); len = strlen(OPERAND(scan)); @@ -423,7 +429,7 @@ bool RegularExpression::compile(const char* exp) * is a trifle forced, but the need to tie the tails of the branches to what * follows makes it hard to avoid. */ -static char* reg(int paren, int* flagp) +char* RegExpCompile::reg(int paren, int* flagp) { char* ret; char* br; @@ -435,22 +441,22 @@ static char* reg(int paren, int* flagp) // Make an OPEN node, if parenthesized. if (paren) { - if (regnpar >= RegularExpression::NSUBEXP) { + if (regnpar >= RegularExpressionMatch::NSUBEXP) { // RAISE Error, SYM(RegularExpression), SYM(Too_Many_Parens), printf("RegularExpression::compile(): Too many parentheses.\n"); - return 0; + return KWSYS_NULLPTR; } parno = regnpar; regnpar++; ret = regnode(static_cast<char>(OPEN + parno)); } else - ret = 0; + ret = KWSYS_NULLPTR; // Pick up the branches, linking them together. br = regbranch(&flags); - if (br == 0) - return (0); - if (ret != 0) + if (br == KWSYS_NULLPTR) + return (KWSYS_NULLPTR); + if (ret != KWSYS_NULLPTR) regtail(ret, br); // OPEN -> first. else ret = br; @@ -460,8 +466,8 @@ static char* reg(int paren, int* flagp) while (*regparse == '|') { regparse++; br = regbranch(&flags); - if (br == 0) - return (0); + if (br == KWSYS_NULLPTR) + return (KWSYS_NULLPTR); regtail(ret, br); // BRANCH -> BRANCH. if (!(flags & HASWIDTH)) *flagp &= ~HASWIDTH; @@ -473,23 +479,23 @@ static char* reg(int paren, int* flagp) regtail(ret, ender); // Hook the tails of the branches to the closing node. - for (br = ret; br != 0; br = regnext(br)) + for (br = ret; br != KWSYS_NULLPTR; br = regnext(br)) regoptail(br, ender); // Check for proper termination. if (paren && *regparse++ != ')') { // RAISE Error, SYM(RegularExpression), SYM(Unmatched_Parens), printf("RegularExpression::compile(): Unmatched parentheses.\n"); - return 0; + return KWSYS_NULLPTR; } else if (!paren && *regparse != '\0') { if (*regparse == ')') { // RAISE Error, SYM(RegularExpression), SYM(Unmatched_Parens), printf("RegularExpression::compile(): Unmatched parentheses.\n"); - return 0; + return KWSYS_NULLPTR; } else { // RAISE Error, SYM(RegularExpression), SYM(Internal_Error), printf("RegularExpression::compile(): Internal error.\n"); - return 0; + return KWSYS_NULLPTR; } // NOTREACHED } @@ -501,7 +507,7 @@ static char* reg(int paren, int* flagp) * * Implements the concatenation operator. */ -static char* regbranch(int* flagp) +char* RegExpCompile::regbranch(int* flagp) { char* ret; char* chain; @@ -511,19 +517,19 @@ static char* regbranch(int* flagp) *flagp = WORST; // Tentatively. ret = regnode(BRANCH); - chain = 0; + chain = KWSYS_NULLPTR; while (*regparse != '\0' && *regparse != '|' && *regparse != ')') { latest = regpiece(&flags); - if (latest == 0) - return (0); + if (latest == KWSYS_NULLPTR) + return (KWSYS_NULLPTR); *flagp |= flags & HASWIDTH; - if (chain == 0) // First piece. + if (chain == KWSYS_NULLPTR) // First piece. *flagp |= flags & SPSTART; else regtail(chain, latest); chain = latest; } - if (chain == 0) // Loop ran zero times. + if (chain == KWSYS_NULLPTR) // Loop ran zero times. regnode(NOTHING); return (ret); @@ -538,7 +544,7 @@ static char* regbranch(int* flagp) * It might seem that this node could be dispensed with entirely, but the * endmarker role is not redundant. */ -static char* regpiece(int* flagp) +char* RegExpCompile::regpiece(int* flagp) { char* ret; char op; @@ -546,8 +552,8 @@ static char* regpiece(int* flagp) int flags; ret = regatom(&flags); - if (ret == 0) - return (0); + if (ret == KWSYS_NULLPTR) + return (KWSYS_NULLPTR); op = *regparse; if (!ISMULT(op)) { @@ -558,7 +564,7 @@ static char* regpiece(int* flagp) if (!(flags & HASWIDTH) && op != '?') { // RAISE Error, SYM(RegularExpression), SYM(Empty_Operand), printf("RegularExpression::compile() : *+ operand could be empty.\n"); - return 0; + return KWSYS_NULLPTR; } *flagp = (op != '+') ? (WORST | SPSTART) : (WORST | HASWIDTH); @@ -592,7 +598,7 @@ static char* regpiece(int* flagp) if (ISMULT(*regparse)) { // RAISE Error, SYM(RegularExpression), SYM(Nested_Operand), printf("RegularExpression::compile(): Nested *?+.\n"); - return 0; + return KWSYS_NULLPTR; } return (ret); } @@ -605,7 +611,7 @@ static char* regpiece(int* flagp) * faster to run. Backslashed characters are exceptions, each becoming a * separate node; the code is simpler that way and it's not worth fixing. */ -static char* regatom(int* flagp) +char* RegExpCompile::regatom(int* flagp) { char* ret; int flags; @@ -645,7 +651,7 @@ static char* regatom(int* flagp) if (rxpclass > rxpclassend + 1) { // RAISE Error, SYM(RegularExpression), SYM(Invalid_Range), printf("RegularExpression::compile(): Invalid range in [].\n"); - return 0; + return KWSYS_NULLPTR; } for (; rxpclass <= rxpclassend; rxpclass++) regc(static_cast<char>(rxpclass)); @@ -658,15 +664,15 @@ static char* regatom(int* flagp) if (*regparse != ']') { // RAISE Error, SYM(RegularExpression), SYM(Unmatched_Bracket), printf("RegularExpression::compile(): Unmatched [].\n"); - return 0; + return KWSYS_NULLPTR; } regparse++; *flagp |= HASWIDTH | SIMPLE; } break; case '(': ret = reg(1, &flags); - if (ret == 0) - return (0); + if (ret == KWSYS_NULLPTR) + return (KWSYS_NULLPTR); *flagp |= flags & (HASWIDTH | SPSTART); break; case '\0': @@ -674,18 +680,18 @@ static char* regatom(int* flagp) case ')': // RAISE Error, SYM(RegularExpression), SYM(Internal_Error), printf("RegularExpression::compile(): Internal error.\n"); // Never here - return 0; + return KWSYS_NULLPTR; case '?': case '+': case '*': // RAISE Error, SYM(RegularExpression), SYM(No_Operand), printf("RegularExpression::compile(): ?+* follows nothing.\n"); - return 0; + return KWSYS_NULLPTR; case '\\': if (*regparse == '\0') { // RAISE Error, SYM(RegularExpression), SYM(Trailing_Backslash), printf("RegularExpression::compile(): Trailing backslash.\n"); - return 0; + return KWSYS_NULLPTR; } ret = regnode(EXACTLY); regc(*regparse++); @@ -701,7 +707,7 @@ static char* regatom(int* flagp) if (len <= 0) { // RAISE Error, SYM(RegularExpression), SYM(Internal_Error), printf("RegularExpression::compile(): Internal error.\n"); - return 0; + return KWSYS_NULLPTR; } ender = *(regparse + len); if (len > 1 && ISMULT(ender)) @@ -724,13 +730,13 @@ static char* regatom(int* flagp) - regnode - emit a node Location. */ -static char* regnode(char op) +char* RegExpCompile::regnode(char op) { char* ret; char* ptr; ret = regcode; - if (ret == ®dummy) { + if (ret == regdummyptr) { regsize += 3; return (ret); } @@ -747,9 +753,9 @@ static char* regnode(char op) /* - regc - emit (if appropriate) a byte of code */ -static void regc(char b) +void RegExpCompile::regc(char b) { - if (regcode != ®dummy) + if (regcode != regdummyptr) *regcode++ = b; else regsize++; @@ -760,13 +766,13 @@ static void regc(char b) * * Means relocating the operand. */ -static void reginsert(char op, char* opnd) +void RegExpCompile::reginsert(char op, char* opnd) { char* src; char* dst; char* place; - if (regcode == ®dummy) { + if (regcode == regdummyptr) { regsize += 3; return; } @@ -786,20 +792,20 @@ static void reginsert(char op, char* opnd) /* - regtail - set the next-pointer at the end of a node chain */ -static void regtail(char* p, const char* val) +void RegExpCompile::regtail(char* p, const char* val) { char* scan; char* temp; int offset; - if (p == ®dummy) + if (p == regdummyptr) return; // Find last node. scan = p; for (;;) { temp = regnext(scan); - if (temp == 0) + if (temp == KWSYS_NULLPTR) break; scan = temp; } @@ -815,10 +821,10 @@ static void regtail(char* p, const char* val) /* - regoptail - regtail on operand of first argument; nop if operandless */ -static void regoptail(char* p, const char* val) +void RegExpCompile::regoptail(char* p, const char* val) { // "Operandless" and "op != BRANCH" are synonymous in practice. - if (p == 0 || p == ®dummy || OP(p) != BRANCH) + if (p == KWSYS_NULLPTR || p == regdummyptr || OP(p) != BRANCH) return; regtail(OPERAND(p), val); } @@ -830,34 +836,30 @@ static void regoptail(char* p, const char* val) //////////////////////////////////////////////////////////////////////// /* - * Global work variables for find(). + * Utility class for RegularExpression::find(). */ -static const char* reginput; // String-input pointer. -static const char* regbol; // Beginning of input, for ^ check. -static const char** regstartp; // Pointer to startp array. -static const char** regendp; // Ditto for endp. +class RegExpFind +{ +public: + const char* reginput; // String-input pointer. + const char* regbol; // Beginning of input, for ^ check. + const char** regstartp; // Pointer to startp array. + const char** regendp; // Ditto for endp. -/* - * Forwards. - */ -static int regtry(const char*, const char**, const char**, const char*); -static int regmatch(const char*); -static int regrepeat(const char*); - -#ifdef DEBUG -int regnarrate = 0; -void regdump(); -static char* regprop(); -#endif + int regtry(const char*, const char**, const char**, const char*); + int regmatch(const char*); + int regrepeat(const char*); +}; // find -- Matches the regular expression to the given string. // Returns true if found, and sets start and end indexes accordingly. - -bool RegularExpression::find(const char* string) +bool RegularExpression::find(char const* string, + RegularExpressionMatch& rmatch) const { const char* s; - this->searchstring = string; + rmatch.clear(); + rmatch.searchstring = string; if (!this->program) { return false; @@ -868,54 +870,57 @@ bool RegularExpression::find(const char* string) // RAISE Error, SYM(RegularExpression), SYM(Internal_Error), printf( "RegularExpression::find(): Compiled regular expression corrupted.\n"); - return 0; + return false; } // If there is a "must appear" string, look for it. - if (this->regmust != 0) { + if (this->regmust != KWSYS_NULLPTR) { s = string; - while ((s = strchr(s, this->regmust[0])) != 0) { + while ((s = strchr(s, this->regmust[0])) != KWSYS_NULLPTR) { if (strncmp(s, this->regmust, this->regmlen) == 0) break; // Found it. s++; } - if (s == 0) // Not present. - return (0); + if (s == KWSYS_NULLPTR) // Not present. + return false; } + RegExpFind regFind; + // Mark beginning of line for ^ . - regbol = string; + regFind.regbol = string; // Simplest case: anchored match need be tried only once. if (this->reganch) - return (regtry(string, this->startp, this->endp, this->program) != 0); + return ( + regFind.regtry(string, rmatch.startp, rmatch.endp, this->program) != 0); // Messy cases: unanchored match. s = string; if (this->regstart != '\0') // We know what char it must start with. - while ((s = strchr(s, this->regstart)) != 0) { - if (regtry(s, this->startp, this->endp, this->program)) - return (1); + while ((s = strchr(s, this->regstart)) != KWSYS_NULLPTR) { + if (regFind.regtry(s, rmatch.startp, rmatch.endp, this->program)) + return true; s++; } else // We don't -- general case. do { - if (regtry(s, this->startp, this->endp, this->program)) - return (1); + if (regFind.regtry(s, rmatch.startp, rmatch.endp, this->program)) + return true; } while (*s++ != '\0'); // Failure. - return (0); + return false; } /* - regtry - try match at specific point 0 failure, 1 success */ -static int regtry(const char* string, const char** start, const char** end, - const char* prog) +int RegExpFind::regtry(const char* string, const char** start, + const char** end, const char* prog) { int i; const char** sp1; @@ -927,9 +932,9 @@ static int regtry(const char* string, const char** start, const char** end, sp1 = start; ep = end; - for (i = RegularExpression::NSUBEXP; i > 0; i--) { - *sp1++ = 0; - *ep++ = 0; + for (i = RegularExpressionMatch::NSUBEXP; i > 0; i--) { + *sp1++ = KWSYS_NULLPTR; + *ep++ = KWSYS_NULLPTR; } if (regmatch(prog + 1)) { start[0] = string; @@ -950,14 +955,14 @@ static int regtry(const char* string, const char** start, const char** end, * by recursion. * 0 failure, 1 success */ -static int regmatch(const char* prog) +int RegExpFind::regmatch(const char* prog) { const char* scan; // Current node. const char* next; // Next node. scan = prog; - while (scan != 0) { + while (scan != KWSYS_NULLPTR) { next = regnext(scan); @@ -989,12 +994,14 @@ static int regmatch(const char* prog) reginput += len; } break; case ANYOF: - if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == 0) + if (*reginput == '\0' || + strchr(OPERAND(scan), *reginput) == KWSYS_NULLPTR) return (0); reginput++; break; case ANYBUT: - if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != 0) + if (*reginput == '\0' || + strchr(OPERAND(scan), *reginput) != KWSYS_NULLPTR) return (0); reginput++; break; @@ -1023,7 +1030,7 @@ static int regmatch(const char* prog) // Don't set startp if some later invocation of the // same parentheses already has. // - if (regstartp[no] == 0) + if (regstartp[no] == KWSYS_NULLPTR) regstartp[no] = save; return (1); } else @@ -1051,7 +1058,7 @@ static int regmatch(const char* prog) // Don't set endp if some later invocation of the // same parentheses already has. // - if (regendp[no] == 0) + if (regendp[no] == KWSYS_NULLPTR) regendp[no] = save; return (1); } else @@ -1071,7 +1078,7 @@ static int regmatch(const char* prog) return (1); reginput = save; scan = regnext(scan); - } while (scan != 0 && OP(scan) == BRANCH); + } while (scan != KWSYS_NULLPTR && OP(scan) == BRANCH); return (0); // NOTREACHED } @@ -1129,7 +1136,7 @@ static int regmatch(const char* prog) /* - regrepeat - repeatedly match something simple, report how many */ -static int regrepeat(const char* p) +int RegExpFind::regrepeat(const char* p) { int count = 0; const char* scan; @@ -1149,13 +1156,13 @@ static int regrepeat(const char* p) } break; case ANYOF: - while (*scan != '\0' && strchr(opnd, *scan) != 0) { + while (*scan != '\0' && strchr(opnd, *scan) != KWSYS_NULLPTR) { count++; scan++; } break; case ANYBUT: - while (*scan != '\0' && strchr(opnd, *scan) == 0) { + while (*scan != '\0' && strchr(opnd, *scan) == KWSYS_NULLPTR) { count++; scan++; } @@ -1176,12 +1183,12 @@ static const char* regnext(const char* p) { int offset; - if (p == ®dummy) - return (0); + if (p == regdummyptr) + return (KWSYS_NULLPTR); offset = NEXT(p); if (offset == 0) - return (0); + return (KWSYS_NULLPTR); if (OP(p) == BACK) return (p - offset); @@ -1193,12 +1200,12 @@ static char* regnext(char* p) { int offset; - if (p == ®dummy) - return (0); + if (p == regdummyptr) + return (KWSYS_NULLPTR); offset = NEXT(p); if (offset == 0) - return (0); + return (KWSYS_NULLPTR); if (OP(p) == BACK) return (p - offset); diff --git a/Source/kwsys/RegularExpression.hxx.in b/Source/kwsys/RegularExpression.hxx.in index 606e3da..3cbbeb8 100644 --- a/Source/kwsys/RegularExpression.hxx.in +++ b/Source/kwsys/RegularExpression.hxx.in @@ -34,6 +34,115 @@ namespace @KWSYS_NAMESPACE@ { +// Forward declaration +class RegularExpression; + +/** \class RegularExpressionMatch + * \brief Stores the pattern matches of a RegularExpression + */ +class @KWSYS_NAMESPACE@_EXPORT RegularExpressionMatch +{ +public: + RegularExpressionMatch(); + + bool isValid() const; + void clear(); + + std::string::size_type start() const; + std::string::size_type end() const; + std::string::size_type start(int n) const; + std::string::size_type end(int n) const; + std::string match(int n) const; + + enum + { + NSUBEXP = 10 + }; + +private: + friend class RegularExpression; + const char* startp[NSUBEXP]; + const char* endp[NSUBEXP]; + const char* searchstring; +}; + +/** + * \brief Creates an invalid match object + */ +inline RegularExpressionMatch::RegularExpressionMatch() +{ + startp[0] = 0; + endp[0] = 0; + searchstring = 0; +} + +/** + * \brief Returns true if the match pointers are valid + */ +inline bool RegularExpressionMatch::isValid() const +{ + return (this->startp[0] != 0); +} + +/** + * \brief Resets to the (invalid) construction state. + */ +inline void RegularExpressionMatch::clear() +{ + startp[0] = 0; + endp[0] = 0; + searchstring = 0; +} + +/** + * \brief Returns the start index of the full match. + */ +inline std::string::size_type RegularExpressionMatch::start() const +{ + return static_cast<std::string::size_type>(this->startp[0] - searchstring); +} + +/** + * \brief Returns the end index of the full match. + */ +inline std::string::size_type RegularExpressionMatch::end() const +{ + return static_cast<std::string::size_type>(this->endp[0] - searchstring); +} + +/** + * \brief Returns the start index of nth submatch. + * start(0) is the start of the full match. + */ +inline std::string::size_type RegularExpressionMatch::start(int n) const +{ + return static_cast<std::string::size_type>(this->startp[n] - + this->searchstring); +} + +/** + * \brief Returns the end index of nth submatch. + * end(0) is the end of the full match. + */ +inline std::string::size_type RegularExpressionMatch::end(int n) const +{ + return static_cast<std::string::size_type>(this->endp[n] - + this->searchstring); +} + +/** + * \brief Returns the nth submatch as a string. + */ +inline std::string RegularExpressionMatch::match(int n) const +{ + if (this->startp[n] == 0) { + return std::string(); + } else { + return std::string(this->startp[n], static_cast<std::string::size_type>( + this->endp[n] - this->startp[n])); + } +} + /** \class RegularExpression * \brief Implements pattern matching with regular expressions. * @@ -93,7 +202,7 @@ namespace @KWSYS_NAMESPACE@ { * * ? Matches preceding pattern zero or once only * - * () Saves a matched expression and uses it in a later match + * () Saves a matched expression and uses it in a later match * * Note that more than one of these metacharacters can be used * in a single regular expression in order to create complex @@ -109,12 +218,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 @@ -170,6 +279,9 @@ namespace @KWSYS_NAMESPACE@ { * the same as the two characters before the first p encounterd in * the line. It would match "drepa qrepb" in "rep drepa qrepb". * + * All methods of RegularExpression can be called simultaneously from + * different threads but only if each invocation uses an own instance of + * RegularExpression. */ class @KWSYS_NAMESPACE@_EXPORT RegularExpression { @@ -213,9 +325,19 @@ public: /** * Matches the regular expression to the given string. + * Returns true if found, and sets start and end indexes + * in the RegularExpressionMatch instance accordingly. + * + * This method is thread safe when called with different + * RegularExpressionMatch instances. + */ + bool find(char const*, RegularExpressionMatch&) const; + + /** + * Matches the regular expression to the given string. * Returns true if found, and sets start and end indexes accordingly. */ - bool find(char const*); + inline bool find(char const*); /** * Matches the regular expression to the given std string. @@ -224,14 +346,18 @@ public: inline bool find(std::string const&); /** - * Index to start of first find. + * Match indices */ + inline RegularExpressionMatch const& regMatch() const; inline std::string::size_type start() const; + inline std::string::size_type end() const; + inline std::string::size_type start(int n) const; + inline std::string::size_type end(int n) const; /** - * Index to end of first find. + * Match strings */ - inline std::string::size_type end() const; + inline std::string match(int n) const; /** * Copy the given regular expression. @@ -266,29 +392,14 @@ public: */ inline void set_invalid(); - /** - * Destructor. - */ - // awf added - std::string::size_type start(int n) const; - std::string::size_type end(int n) const; - std::string match(int n) const; - - enum - { - NSUBEXP = 10 - }; - private: - const char* startp[NSUBEXP]; - const char* endp[NSUBEXP]; + RegularExpressionMatch regmatch; char regstart; // Internal use only char reganch; // Internal use only const char* regmust; // Internal use only std::string::size_type regmlen; // Internal use only char* program; int progsize; - const char* searchstring; }; /** @@ -344,51 +455,42 @@ inline bool RegularExpression::compile(std::string const& s) * Matches the regular expression to the given std string. * Returns true if found, and sets start and end indexes accordingly. */ -inline bool RegularExpression::find(std::string const& s) +inline bool RegularExpression::find(const char* s) { - return this->find(s.c_str()); + return this->find(s, this->regmatch); } /** - * Set the start position for the regular expression. + * Matches the regular expression to the given std string. + * Returns true if found, and sets start and end indexes accordingly. */ -inline std::string::size_type RegularExpression::start() const +inline bool RegularExpression::find(std::string const& s) { - return static_cast<std::string::size_type>(this->startp[0] - searchstring); + return this->find(s.c_str()); } /** - * Returns the start/end index of the last item found. + * Returns the internal match object */ -inline std::string::size_type RegularExpression::end() const +inline RegularExpressionMatch const& RegularExpression::regMatch() const { - return static_cast<std::string::size_type>(this->endp[0] - searchstring); + return this->regmatch; } /** - * Returns true if two regular expressions have different - * compiled program for pattern matching. + * Returns the start index of the full match. */ -inline bool RegularExpression::operator!=(const RegularExpression& r) const +inline std::string::size_type RegularExpression::start() const { - return (!(*this == r)); + return regmatch.start(); } /** - * Returns true if a valid regular expression is compiled - * and ready for pattern matching. + * Returns the end index of the full match. */ -inline bool RegularExpression::is_valid() const -{ - return (this->program != 0); -} - -inline void RegularExpression::set_invalid() +inline std::string::size_type RegularExpression::end() const { - //#ifndef _WIN32 - delete[] this->program; - //#endif - this->program = 0; + return regmatch.end(); } /** @@ -396,7 +498,7 @@ inline void RegularExpression::set_invalid() */ inline std::string::size_type RegularExpression::start(int n) const { - return static_cast<std::string::size_type>(this->startp[n] - searchstring); + return regmatch.start(n); } /** @@ -404,7 +506,7 @@ inline std::string::size_type RegularExpression::start(int n) const */ inline std::string::size_type RegularExpression::end(int n) const { - return static_cast<std::string::size_type>(this->endp[n] - searchstring); + return regmatch.end(n); } /** @@ -412,12 +514,33 @@ inline std::string::size_type RegularExpression::end(int n) const */ inline std::string RegularExpression::match(int n) const { - if (this->startp[n] == 0) { - return std::string(""); - } else { - return std::string(this->startp[n], static_cast<std::string::size_type>( - this->endp[n] - this->startp[n])); - } + return regmatch.match(n); +} + +/** + * Returns true if two regular expressions have different + * compiled program for pattern matching. + */ +inline bool RegularExpression::operator!=(const RegularExpression& r) const +{ + return (!(*this == r)); +} + +/** + * Returns true if a valid regular expression is compiled + * and ready for pattern matching. + */ +inline bool RegularExpression::is_valid() const +{ + return (this->program != 0); +} + +inline void RegularExpression::set_invalid() +{ + //#ifndef _WIN32 + delete[] this->program; + //#endif + this->program = 0; } } // namespace @KWSYS_NAMESPACE@ diff --git a/Source/kwsys/SharedForward.h.in b/Source/kwsys/SharedForward.h.in index f638267..0caf5e7 100644 --- a/Source/kwsys/SharedForward.h.in +++ b/Source/kwsys/SharedForward.h.in @@ -225,7 +225,7 @@ static const char kwsys_shared_forward_path_slash[2] = { #define KWSYS_SHARED_FORWARD_LDD_N 1 #define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" -/* OSX */ +/* OS X */ #elif defined(__APPLE__) #define KWSYS_SHARED_FORWARD_LDD "otool", "-L" #define KWSYS_SHARED_FORWARD_LDD_N 2 diff --git a/Source/kwsys/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx index 86fdccd..2b9d7b1 100644 --- a/Source/kwsys/SystemInformation.cxx +++ b/Source/kwsys/SystemInformation.cxx @@ -121,7 +121,11 @@ typedef int siginfo_t; #if defined(KWSYS_SYS_HAS_IFADDRS_H) #include <ifaddrs.h> #include <net/if.h> -#if !defined(__LSB_VERSION__) /* LSB has no getifaddrs */ +#if defined(__LSB_VERSION__) +/* LSB has no getifaddrs */ +#elif defined(__ANDROID_API__) && __ANDROID_API__ < 24 +/* Android has no getifaddrs prior to API 24. */ +#else #define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN #endif #endif @@ -340,7 +344,7 @@ public: bool DoesCPUSupportCPUID(); - // Retrieve memory information in megabyte. + // Retrieve memory information in MiB. size_t GetTotalVirtualMemory(); size_t GetAvailableVirtualMemory(); size_t GetTotalPhysicalMemory(); @@ -348,7 +352,7 @@ public: LongLong GetProcessId(); - // Retrieve memory information in kib + // Retrieve memory information in KiB. LongLong GetHostMemoryTotal(); LongLong GetHostMemoryAvailable(const char* envVarName); LongLong GetHostMemoryUsed(); @@ -736,7 +740,7 @@ bool SystemInformation::DoesCPUSupportCPUID() return this->Implementation->DoesCPUSupportCPUID(); } -// Retrieve memory information in megabyte. +// Retrieve memory information in MiB. size_t SystemInformation::GetTotalVirtualMemory() { return this->Implementation->GetTotalVirtualMemory(); @@ -881,7 +885,7 @@ int LoadLines(FILE* file, std::vector<std::string>& lines) char buf[bufSize] = { '\0' }; while (!feof(file) && !ferror(file)) { errno = 0; - if (fgets(buf, bufSize, file) == 0) { + if (fgets(buf, bufSize, file) == KWSYS_NULLPTR) { if (ferror(file) && (errno == EINTR)) { clearerr(file); } @@ -977,7 +981,7 @@ int GetFieldsFromCommand(const char* command, const char** fieldNames, T* values) { FILE* file = popen(command, "r"); - if (file == 0) { + if (file == KWSYS_NULLPTR) { return -1; } std::vector<std::string> fields; @@ -987,7 +991,7 @@ int GetFieldsFromCommand(const char* command, const char** fieldNames, return -1; } int i = 0; - while (fieldNames[i] != NULL) { + while (fieldNames[i] != KWSYS_NULLPTR) { int ierr = NameValue(fields, fieldNames[i], values[i]); if (ierr) { return -(i + 2); @@ -1023,7 +1027,8 @@ void StacktraceSignalHandler(int sigNo, siginfo_t* sigInfo, break; case SIGFPE: - oss << "Caught SIGFPE at " << (sigInfo->si_addr == 0 ? "0x" : "") + oss << "Caught SIGFPE at " + << (sigInfo->si_addr == KWSYS_NULLPTR ? "0x" : "") << sigInfo->si_addr << " "; switch (sigInfo->si_code) { #if defined(FPE_INTDIV) @@ -1071,7 +1076,8 @@ void StacktraceSignalHandler(int sigNo, siginfo_t* sigInfo, break; case SIGSEGV: - oss << "Caught SIGSEGV at " << (sigInfo->si_addr == 0 ? "0x" : "") + oss << "Caught SIGSEGV at " + << (sigInfo->si_addr == KWSYS_NULLPTR ? "0x" : "") << sigInfo->si_addr << " "; switch (sigInfo->si_code) { case SEGV_MAPERR: @@ -1089,7 +1095,8 @@ void StacktraceSignalHandler(int sigNo, siginfo_t* sigInfo, break; case SIGBUS: - oss << "Caught SIGBUS at " << (sigInfo->si_addr == 0 ? "0x" : "") + oss << "Caught SIGBUS at " + << (sigInfo->si_addr == KWSYS_NULLPTR ? "0x" : "") << sigInfo->si_addr << " "; switch (sigInfo->si_code) { case BUS_ADRALN: @@ -1129,7 +1136,8 @@ void StacktraceSignalHandler(int sigNo, siginfo_t* sigInfo, break; case SIGILL: - oss << "Caught SIGILL at " << (sigInfo->si_addr == 0 ? "0x" : "") + oss << "Caught SIGILL at " + << (sigInfo->si_addr == KWSYS_NULLPTR ? "0x" : "") << sigInfo->si_addr << " "; switch (sigInfo->si_code) { case ILL_ILLOPC: @@ -1313,8 +1321,8 @@ SymbolProperties::SymbolProperties() // not using an initializer list // to avoid some PGI compiler warnings this->SetBinary("???"); - this->SetBinaryBaseAddress(NULL); - this->Address = NULL; + this->SetBinaryBaseAddress(KWSYS_NULLPTR); + this->Address = KWSYS_NULLPTR; this->SetSourceFile("???"); this->SetFunction("???"); this->SetLineNumber(-1); @@ -1346,7 +1354,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 { @@ -1649,7 +1657,7 @@ int SystemInformationImplementation::GetFullyQualifiedDomainName( // any number of interfaces on this system we look for the // first of these that contains the name returned by gethostname // and is longer. failing that we return gethostname and indicate - // with a failure code. Return of a failure code is not necessarilly + // with a failure code. Return of a failure code is not necessarily // an indication of an error. for instance gethostname may return // the fully qualified domain name, or there may not be one if the // system lives on a private network such as in the case of a cluster @@ -1671,7 +1679,7 @@ int SystemInformationImplementation::GetFullyQualifiedDomainName( return -2; } - for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) { + for (ifa = ifas; ifa != KWSYS_NULLPTR; ifa = ifa->ifa_next) { int fam = ifa->ifa_addr ? ifa->ifa_addr->sa_family : -1; // Skip Loopback interfaces if (((fam == AF_INET) || (fam == AF_INET6)) && @@ -1682,7 +1690,7 @@ int SystemInformationImplementation::GetFullyQualifiedDomainName( : sizeof(struct sockaddr_in6)); ierr = getnameinfo(ifa->ifa_addr, static_cast<socklen_t>(addrlen), host, - NI_MAXHOST, NULL, 0, NI_NAMEREQD); + NI_MAXHOST, KWSYS_NULLPTR, 0, NI_NAMEREQD); if (ierr) { // don't report the failure now since we may succeed on another // interface. If all attempts fail then return the failure code. @@ -3609,7 +3617,7 @@ SystemInformationImplementation::GetHostMemoryTotal() #elif defined(__APPLE__) uint64_t mem; size_t len = sizeof(mem); - int ierr = sysctlbyname("hw.memsize", &mem, &len, NULL, 0); + int ierr = sysctlbyname("hw.memsize", &mem, &len, KWSYS_NULLPTR, 0); if (ierr) { return -1; } @@ -3633,7 +3641,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); @@ -3752,7 +3760,8 @@ SystemInformationImplementation::GetHostMemoryUsed() if (psz < 1) { return -1; } - const char* names[3] = { "Pages wired down:", "Pages active:", NULL }; + const char* names[3] = { "Pages wired down:", "Pages active:", + KWSYS_NULLPTR }; SystemInformation::LongLong values[2] = { SystemInformation::LongLong(0) }; int ierr = GetFieldsFromCommand("vm_stat", names, values); if (ierr) { @@ -3800,7 +3809,7 @@ SystemInformationImplementation::GetProcMemoryUsed() std::ostringstream oss; oss << "ps -o rss= -p " << pid; FILE* file = popen(oss.str().c_str(), "r"); - if (file == 0) { + if (file == KWSYS_NULLPTR) { return -1; } oss.str(""); @@ -3933,13 +3942,13 @@ void SystemInformationImplementation::SetStackTraceOnError(int enable) if (enable && !saOrigValid) { // save the current actions - sigaction(SIGABRT, 0, &saABRTOrig); - sigaction(SIGSEGV, 0, &saSEGVOrig); - sigaction(SIGTERM, 0, &saTERMOrig); - sigaction(SIGINT, 0, &saINTOrig); - sigaction(SIGILL, 0, &saILLOrig); - sigaction(SIGBUS, 0, &saBUSOrig); - sigaction(SIGFPE, 0, &saFPEOrig); + sigaction(SIGABRT, KWSYS_NULLPTR, &saABRTOrig); + sigaction(SIGSEGV, KWSYS_NULLPTR, &saSEGVOrig); + sigaction(SIGTERM, KWSYS_NULLPTR, &saTERMOrig); + sigaction(SIGINT, KWSYS_NULLPTR, &saINTOrig); + sigaction(SIGILL, KWSYS_NULLPTR, &saILLOrig); + sigaction(SIGBUS, KWSYS_NULLPTR, &saBUSOrig); + sigaction(SIGFPE, KWSYS_NULLPTR, &saFPEOrig); // enable read, disable write saOrigValid = 1; @@ -3953,22 +3962,22 @@ void SystemInformationImplementation::SetStackTraceOnError(int enable) #endif sigemptyset(&sa.sa_mask); - sigaction(SIGABRT, &sa, 0); - sigaction(SIGSEGV, &sa, 0); - sigaction(SIGTERM, &sa, 0); - sigaction(SIGINT, &sa, 0); - sigaction(SIGILL, &sa, 0); - sigaction(SIGBUS, &sa, 0); - sigaction(SIGFPE, &sa, 0); + sigaction(SIGABRT, &sa, KWSYS_NULLPTR); + sigaction(SIGSEGV, &sa, KWSYS_NULLPTR); + sigaction(SIGTERM, &sa, KWSYS_NULLPTR); + sigaction(SIGINT, &sa, KWSYS_NULLPTR); + sigaction(SIGILL, &sa, KWSYS_NULLPTR); + sigaction(SIGBUS, &sa, KWSYS_NULLPTR); + sigaction(SIGFPE, &sa, KWSYS_NULLPTR); } else if (!enable && saOrigValid) { // restore previous actions - sigaction(SIGABRT, &saABRTOrig, 0); - sigaction(SIGSEGV, &saSEGVOrig, 0); - sigaction(SIGTERM, &saTERMOrig, 0); - sigaction(SIGINT, &saINTOrig, 0); - sigaction(SIGILL, &saILLOrig, 0); - sigaction(SIGBUS, &saBUSOrig, 0); - sigaction(SIGFPE, &saFPEOrig, 0); + sigaction(SIGABRT, &saABRTOrig, KWSYS_NULLPTR); + sigaction(SIGSEGV, &saSEGVOrig, KWSYS_NULLPTR); + sigaction(SIGTERM, &saTERMOrig, KWSYS_NULLPTR); + sigaction(SIGINT, &saINTOrig, KWSYS_NULLPTR); + sigaction(SIGILL, &saILLOrig, KWSYS_NULLPTR); + sigaction(SIGBUS, &saBUSOrig, KWSYS_NULLPTR); + sigaction(SIGFPE, &saFPEOrig, KWSYS_NULLPTR); // enable write, disable read saOrigValid = 0; @@ -4404,7 +4413,7 @@ bool SystemInformationImplementation::ParseSysCtl() int err = 0; uint64_t value = 0; size_t len = sizeof(value); - sysctlbyname("hw.memsize", &value, &len, NULL, 0); + sysctlbyname("hw.memsize", &value, &len, KWSYS_NULLPTR, 0); this->TotalPhysicalMemory = static_cast<size_t>(value / 1048576); // Parse values for Mac @@ -4414,7 +4423,7 @@ bool SystemInformationImplementation::ParseSysCtl() if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vmstat, &count) == KERN_SUCCESS) { len = sizeof(value); - err = sysctlbyname("hw.pagesize", &value, &len, NULL, 0); + err = sysctlbyname("hw.pagesize", &value, &len, KWSYS_NULLPTR, 0); int64_t available_memory = vmstat.free_count * value; this->AvailablePhysicalMemory = static_cast<size_t>(available_memory / 1048576); @@ -4426,7 +4435,7 @@ bool SystemInformationImplementation::ParseSysCtl() size_t miblen = sizeof(mib) / sizeof(mib[0]); struct xsw_usage swap; len = sizeof(swap); - err = sysctl(mib, miblen, &swap, &len, NULL, 0); + err = sysctl(mib, miblen, &swap, &len, KWSYS_NULLPTR, 0); if (err == 0) { this->AvailableVirtualMemory = static_cast<size_t>(swap.xsu_avail / 1048576); @@ -4439,71 +4448,75 @@ bool SystemInformationImplementation::ParseSysCtl() // CPU Info len = sizeof(this->NumberOfPhysicalCPU); - sysctlbyname("hw.physicalcpu", &this->NumberOfPhysicalCPU, &len, NULL, 0); + sysctlbyname("hw.physicalcpu", &this->NumberOfPhysicalCPU, &len, + KWSYS_NULLPTR, 0); len = sizeof(this->NumberOfLogicalCPU); - sysctlbyname("hw.logicalcpu", &this->NumberOfLogicalCPU, &len, NULL, 0); + sysctlbyname("hw.logicalcpu", &this->NumberOfLogicalCPU, &len, KWSYS_NULLPTR, + 0); int cores_per_package = 0; len = sizeof(cores_per_package); err = sysctlbyname("machdep.cpu.cores_per_package", &cores_per_package, &len, - NULL, 0); + KWSYS_NULLPTR, 0); // That name was not found, default to 1 this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = err != 0 ? 1 : static_cast<unsigned char>(cores_per_package); len = sizeof(value); - sysctlbyname("hw.cpufrequency", &value, &len, NULL, 0); + sysctlbyname("hw.cpufrequency", &value, &len, KWSYS_NULLPTR, 0); this->CPUSpeedInMHz = static_cast<float>(value) / 1000000; // Chip family len = sizeof(this->ChipID.Family); // Seems only the intel chips will have this name so if this fails it is // probably a PPC machine - err = - sysctlbyname("machdep.cpu.family", &this->ChipID.Family, &len, NULL, 0); + err = sysctlbyname("machdep.cpu.family", &this->ChipID.Family, &len, + KWSYS_NULLPTR, 0); if (err != 0) // Go back to names we know but are less descriptive { this->ChipID.Family = 0; ::memset(retBuf, 0, 128); len = 32; - err = sysctlbyname("hw.machine", &retBuf, &len, NULL, 0); + err = sysctlbyname("hw.machine", &retBuf, &len, KWSYS_NULLPTR, 0); std::string machineBuf(retBuf); if (machineBuf.find_first_of("Power") != std::string::npos) { this->ChipID.Vendor = "IBM"; len = sizeof(this->ChipID.Family); - err = sysctlbyname("hw.cputype", &this->ChipID.Family, &len, NULL, 0); + err = sysctlbyname("hw.cputype", &this->ChipID.Family, &len, + KWSYS_NULLPTR, 0); len = sizeof(this->ChipID.Model); - err = sysctlbyname("hw.cpusubtype", &this->ChipID.Model, &len, NULL, 0); + err = sysctlbyname("hw.cpusubtype", &this->ChipID.Model, &len, + KWSYS_NULLPTR, 0); this->FindManufacturer(); } } else // Should be an Intel Chip. { len = sizeof(this->ChipID.Family); - err = - sysctlbyname("machdep.cpu.family", &this->ChipID.Family, &len, NULL, 0); + err = sysctlbyname("machdep.cpu.family", &this->ChipID.Family, &len, + KWSYS_NULLPTR, 0); ::memset(retBuf, 0, 128); len = 128; - err = sysctlbyname("machdep.cpu.vendor", retBuf, &len, NULL, 0); + err = sysctlbyname("machdep.cpu.vendor", retBuf, &len, KWSYS_NULLPTR, 0); // Chip Vendor this->ChipID.Vendor = retBuf; this->FindManufacturer(); // Chip Model len = sizeof(value); - err = sysctlbyname("machdep.cpu.model", &value, &len, NULL, 0); + err = sysctlbyname("machdep.cpu.model", &value, &len, KWSYS_NULLPTR, 0); this->ChipID.Model = static_cast<int>(value); // Chip Stepping len = sizeof(value); value = 0; - err = sysctlbyname("machdep.cpu.stepping", &value, &len, NULL, 0); + err = sysctlbyname("machdep.cpu.stepping", &value, &len, KWSYS_NULLPTR, 0); if (!err) { this->ChipID.Revision = static_cast<int>(value); } // feature string - char* buf = 0; + char* buf = KWSYS_NULLPTR; size_t allocSize = 128; err = 0; @@ -4520,7 +4533,8 @@ bool SystemInformationImplementation::ParseSysCtl() } buf[0] = ' '; len = allocSize - 2; // keep space for leading and trailing space - err = sysctlbyname("machdep.cpu.features", buf + 1, &len, NULL, 0); + err = + sysctlbyname("machdep.cpu.features", buf + 1, &len, KWSYS_NULLPTR, 0); } if (!err && buf && len) { // now we can match every flags as space + flag + space @@ -4561,7 +4575,8 @@ bool SystemInformationImplementation::ParseSysCtl() // brand string ::memset(retBuf, 0, sizeof(retBuf)); len = sizeof(retBuf); - err = sysctlbyname("machdep.cpu.brand_string", retBuf, &len, NULL, 0); + err = + sysctlbyname("machdep.cpu.brand_string", retBuf, &len, KWSYS_NULLPTR, 0); if (!err) { this->ChipID.ProcessorName = retBuf; this->ChipID.ModelName = retBuf; @@ -4569,10 +4584,10 @@ bool SystemInformationImplementation::ParseSysCtl() // Cache size len = sizeof(value); - err = sysctlbyname("hw.l1icachesize", &value, &len, NULL, 0); + err = sysctlbyname("hw.l1icachesize", &value, &len, KWSYS_NULLPTR, 0); this->Features.L1CacheSize = static_cast<int>(value); len = sizeof(value); - err = sysctlbyname("hw.l2cachesize", &value, &len, NULL, 0); + err = sysctlbyname("hw.l2cachesize", &value, &len, KWSYS_NULLPTR, 0); this->Features.L2CacheSize = static_cast<int>(value); return true; @@ -4609,7 +4624,7 @@ std::string SystemInformationImplementation::RunProcess( kwsysProcess_Execute(gp); - char* data = NULL; + char* data = KWSYS_NULLPTR; int length; double timeout = 255; int pipe; // pipe id as returned by kwsysProcess_WaitForData() @@ -4621,7 +4636,7 @@ std::string SystemInformationImplementation::RunProcess( { buffer.append(data, length); } - kwsysProcess_WaitForExit(gp, 0); + kwsysProcess_WaitForExit(gp, KWSYS_NULLPTR); int result = 0; switch (kwsysProcess_GetState(gp)) { @@ -4694,7 +4709,7 @@ std::string SystemInformationImplementation::ParseValueFromKStat( std::string lastArg = command.substr(start + 1, command.size() - start - 1); args.push_back(lastArg.c_str()); - args.push_back(0); + args.push_back(KWSYS_NULLPTR); std::string buffer = this->RunProcess(args); @@ -5379,7 +5394,7 @@ int SystemInformationImplementation::CallSwVers(const char* arg, std::vector<const char*> args; args.push_back("sw_vers"); args.push_back(arg); - args.push_back(0); + args.push_back(KWSYS_NULLPTR); ver = this->RunProcess(args); this->TrimNewline(ver); #else diff --git a/Source/kwsys/SystemInformation.hxx.in b/Source/kwsys/SystemInformation.hxx.in index 516c505..fe7e8b5 100644 --- a/Source/kwsys/SystemInformation.hxx.in +++ b/Source/kwsys/SystemInformation.hxx.in @@ -103,14 +103,14 @@ public: // Retrieve id of the current running process LongLong GetProcessId(); - // Retrieve memory information in megabyte. + // Retrieve memory information in MiB. size_t GetTotalVirtualMemory(); size_t GetAvailableVirtualMemory(); size_t GetTotalPhysicalMemory(); size_t GetAvailablePhysicalMemory(); // returns an informative general description if the installed and - // available ram on this system. See the GetHostMmeoryTotal, and + // available ram on this system. See the GetHostMemoryTotal, and // Get{Host,Proc}MemoryAvailable methods for more information. std::string GetMemoryDescription(const char* hostLimitEnvVarName = NULL, const char* procLimitEnvVarName = NULL); @@ -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..106afe5 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -20,6 +20,7 @@ #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> @@ -105,7 +106,8 @@ extern char** environ; // getpwnam doesn't exist on Windows and Cray Xt3/Catamount // same for TIOCGWINSZ -#if defined(_WIN32) || defined(__LIBCATAMOUNT__) +#if defined(_WIN32) || defined(__LIBCATAMOUNT__) || \ + (defined(HAVE_GETPWNAM) && HAVE_GETPWNAM == 0) #undef HAVE_GETPWNAM #undef HAVE_TTY_INFO #else @@ -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; } @@ -300,7 +306,7 @@ inline int Chdir(const std::string& dir) return chdir(dir.c_str()); } inline void Realpath(const std::string& path, std::string& resolved_path, - std::string* errorMessage = 0) + std::string* errorMessage = KWSYS_NULLPTR) { char resolved_name[KWSYS_SYSTEMTOOLS_MAXPATH]; @@ -346,7 +352,7 @@ double SystemTools::GetTime(void) 11644473600.0); #else struct timeval t; - gettimeofday(&t, 0); + gettimeofday(&t, KWSYS_NULLPTR); return 1.0 * double(t.tv_sec) + 0.000001 * double(t.tv_usec); #endif } @@ -408,7 +414,7 @@ public: const envchar* Release(const envchar* env) { - const envchar* old = 0; + const envchar* old = KWSYS_NULLPTR; iterator i = this->find(env); if (i != this->end()) { old = *i; @@ -483,7 +489,7 @@ void SystemTools::GetPath(std::vector<std::string>& path, const char* env) const char* SystemTools::GetEnvImpl(const char* key) { - const char* v = 0; + const char* v = KWSYS_NULLPTR; #if defined(_WIN32) std::string env; if (SystemTools::GetEnv(key, env)) { @@ -539,7 +545,7 @@ bool SystemTools::HasEnv(const char* key) #else const char* v = getenv(key); #endif - return v != 0; + return v != KWSYS_NULLPTR; } bool SystemTools::HasEnv(const std::string& key) @@ -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 != KWSYS_NULLPTR) { + 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 != KWSYS_NULLPTR) { + SystemTools::SetPermissions(topdir, *mode); } + return true; } @@ -1059,7 +1072,7 @@ bool SystemTools::WriteRegistryValue(const std::string&, const std::string&, // HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath // => will delete the data of the "default" value of the key // HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root -// => will delete the data of the "Root" value of the key +// => will delete the data of the "Root" value of the key #if defined(_WIN32) && !defined(__CYGWIN__) bool SystemTools::DeleteRegistryValue(const std::string& key, KeyWOW64 view) @@ -1507,7 +1520,7 @@ char* SystemTools::AppendStrings(const char* str1, const char* str2) size_t len1 = strlen(str1); char* newstr = new char[len1 + strlen(str2) + 1]; if (!newstr) { - return 0; + return KWSYS_NULLPTR; } strcpy(newstr, str1); strcat(newstr + len1, str2); @@ -1530,7 +1543,7 @@ char* SystemTools::AppendStrings(const char* str1, const char* str2, size_t len1 = strlen(str1), len2 = strlen(str2); char* newstr = new char[len1 + len2 + strlen(str3) + 1]; if (!newstr) { - return 0; + return KWSYS_NULLPTR; } strcpy(newstr, str1); strcat(newstr + len1, str2); @@ -1580,7 +1593,7 @@ size_t SystemTools::CountChar(const char* str, char c) char* SystemTools::RemoveChars(const char* str, const char* toremove) { if (!str) { - return NULL; + return KWSYS_NULLPTR; } char* clean_str = new char[strlen(str) + 1]; char* ptr = clean_str; @@ -1602,7 +1615,7 @@ char* SystemTools::RemoveChars(const char* str, const char* toremove) char* SystemTools::RemoveCharsButUpperHex(const char* str) { if (!str) { - return 0; + return KWSYS_NULLPTR; } char* clean_str = new char[strlen(str) + 1]; char* ptr = clean_str; @@ -1679,11 +1692,11 @@ 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) { - return NULL; + return KWSYS_NULLPTR; } size_t len1 = strlen(str1), len2 = strlen(str2); @@ -1696,7 +1709,7 @@ const char* SystemTools::FindLastString(const char* str1, const char* str2) } while (ptr-- != str1); } - return NULL; + return KWSYS_NULLPTR; } // Duplicate string @@ -1706,7 +1719,7 @@ char* SystemTools::DuplicateString(const char* str) char* newstr = new char[strlen(str) + 1]; return strcpy(newstr, str); } - return NULL; + return KWSYS_NULLPTR; } // Return a cropped string @@ -1870,21 +1883,23 @@ static void ConvertVMSToUnix(std::string& path) // convert windows slashes to unix slashes void SystemTools::ConvertToUnixSlashes(std::string& path) { + if (path.empty()) { + return; + } + const char* pathCString = path.c_str(); bool hasDoubleSlash = false; #ifdef __VMS ConvertVMSToUnix(path); #else const char* pos0 = pathCString; - const char* pos1 = pathCString + 1; for (std::string::size_type pos = 0; *pos0; ++pos) { - // make sure we don't convert an escaped space to a unix slash - if (*pos0 == '\\' && *pos1 != ' ') { + if (*pos0 == '\\') { path[pos] = '/'; } // Also, reuse the loop to check for slash followed by another slash - if (*pos1 == '/' && *(pos1 + 1) == '/' && !hasDoubleSlash) { + if (!hasDoubleSlash && *(pos0 + 1) == '/' && *(pos0 + 2) == '/') { #ifdef _WIN32 // However, on windows if the first characters are both slashes, // then keep them that way, so that network paths can be handled. @@ -1897,43 +1912,41 @@ void SystemTools::ConvertToUnixSlashes(std::string& path) } pos0++; - pos1++; } if (hasDoubleSlash) { SystemTools::ReplaceString(path, "//", "/"); } #endif + // remove any trailing slash - if (!path.empty()) { - // if there is a tilda ~ then replace it with HOME - pathCString = path.c_str(); - if (pathCString[0] == '~' && - (pathCString[1] == '/' || pathCString[1] == '\0')) { - std::string homeEnv; - if (SystemTools::GetEnv("HOME", homeEnv)) { - path.replace(0, 1, homeEnv); - } + // if there is a tilda ~ then replace it with HOME + pathCString = path.c_str(); + if (pathCString[0] == '~' && + (pathCString[1] == '/' || pathCString[1] == '\0')) { + std::string homeEnv; + if (SystemTools::GetEnv("HOME", homeEnv)) { + path.replace(0, 1, homeEnv); } + } #ifdef HAVE_GETPWNAM - else if (pathCString[0] == '~') { - std::string::size_type idx = path.find_first_of("/\0"); - std::string user = path.substr(1, idx - 1); - passwd* pw = getpwnam(user.c_str()); - if (pw) { - path.replace(0, idx, pw->pw_dir); - } + else if (pathCString[0] == '~') { + std::string::size_type idx = path.find_first_of("/\0"); + std::string user = path.substr(1, idx - 1); + passwd* pw = getpwnam(user.c_str()); + if (pw) { + path.replace(0, idx, pw->pw_dir); } + } #endif - // remove trailing slash if the path is more than - // a single / - pathCString = path.c_str(); - size_t size = path.size(); - if (size > 1 && *path.rbegin() == '/') { - // if it is c:/ then do not remove the trailing slash - if (!((size == 3 && pathCString[1] == ':'))) { - path.resize(size - 1); - } + // remove trailing slash if the path is more than + // a single / + pathCString = path.c_str(); + size_t size = path.size(); + if (size > 1 && *path.rbegin() == '/') { + // if it is c:/ then do not remove the trailing slash + if (!((size == 3 && pathCString[1] == ':'))) { + path.resize(size - 1); } } } @@ -2496,6 +2509,14 @@ bool SystemTools::RemoveFile(const std::string& source) if (IsJunction(ws) && DeleteJunction(ws)) { return true; } + const DWORD DIRECTORY_SOFT_LINK_ATTRS = + FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT; + DWORD attrs = GetFileAttributesW(ws.c_str()); + if (attrs != INVALID_FILE_ATTRIBUTES && + (attrs & DIRECTORY_SOFT_LINK_ATTRS) == DIRECTORY_SOFT_LINK_ATTRS && + RemoveDirectoryW(ws.c_str())) { + return true; + } if (DeleteFileW(ws.c_str()) || GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND) { return true; @@ -3079,7 +3100,7 @@ bool SystemTools::FindProgramPath(const char* argv0, std::string& pathOut, std::string SystemTools::CollapseFullPath(const std::string& in_relative) { - return SystemTools::CollapseFullPath(in_relative, 0); + return SystemTools::CollapseFullPath(in_relative, KWSYS_NULLPTR); } void SystemTools::AddTranslationPath(const std::string& a, @@ -3149,8 +3170,8 @@ void SystemTools::CheckTranslationPath(std::string& path) static void SystemToolsAppendComponents( std::vector<std::string>& out_components, - std::vector<std::string>::const_iterator first, - std::vector<std::string>::const_iterator last) + std::vector<std::string>::iterator first, + std::vector<std::string>::iterator last) { static const std::string up = ".."; static const std::string cur = "."; @@ -3160,7 +3181,11 @@ static void SystemToolsAppendComponents( out_components.resize(out_components.size() - 1); } } else if (!i->empty() && *i != cur) { +#if __cplusplus >= 201103L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201103L) + out_components.push_back(std::move(*i)); +#else out_components.push_back(*i); +#endif } } } @@ -3168,63 +3193,18 @@ static void SystemToolsAppendComponents( std::string SystemTools::CollapseFullPath(const std::string& in_path, const char* in_base) { - // Collect the output path components. - std::vector<std::string> out_components; - - // Split the input path components. - std::vector<std::string> path_components; - SystemTools::SplitPath(in_path, path_components); - - // If the input path is relative, start with a base path. - if (path_components[0].empty()) { - std::vector<std::string> base_components; - if (in_base) { - // Use the given base path. - SystemTools::SplitPath(in_base, base_components); + // Use the current working directory as a base path. + char buf[2048]; + const char* res_in_base = in_base; + if (!res_in_base) { + if (const char* cwd = Getcwd(buf, 2048)) { + res_in_base = cwd; } else { - // Use the current working directory as a base path. - char buf[2048]; - if (const char* cwd = Getcwd(buf, 2048)) { - SystemTools::SplitPath(cwd, base_components); - } else { - base_components.push_back(""); - } + res_in_base = ""; } - - // Append base path components to the output path. - out_components.push_back(base_components[0]); - SystemToolsAppendComponents(out_components, base_components.begin() + 1, - base_components.end()); } - // Append input path components to the output path. - SystemToolsAppendComponents(out_components, path_components.begin(), - path_components.end()); - - // Transform the path back to a string. - std::string newPath = SystemTools::JoinPath(out_components); - - // Update the translation table with this potentially new path. I am not - // sure why this line is here, it seems really questionable, but yet I - // would put good money that if I remove it something will break, basically - // from what I can see it created a mapping from the collapsed path, to be - // replaced by the input path, which almost completely does the opposite of - // this function, the only thing preventing this from happening a lot is - // that if the in_path has a .. in it, then it is not added to the - // translation table. So for most calls this either does nothing due to the - // .. or it adds a translation between identical paths as nothing was - // collapsed, so I am going to try to comment it out, and see what hits the - // fan, hopefully quickly. - // Commented out line below: - // SystemTools::AddTranslationPath(newPath, in_path); - - SystemTools::CheckTranslationPath(newPath); -#ifdef _WIN32 - newPath = SystemTools::GetActualCaseForPath(newPath); - SystemTools::ConvertToUnixSlashes(newPath); -#endif - // Return the reconstructed path. - return newPath; + return SystemTools::CollapseFullPath(in_path, std::string(res_in_base)); } std::string SystemTools::CollapseFullPath(const std::string& in_path, @@ -3236,9 +3216,10 @@ std::string SystemTools::CollapseFullPath(const std::string& in_path, // Split the input path components. std::vector<std::string> path_components; SystemTools::SplitPath(in_path, path_components); + out_components.reserve(path_components.size()); // If the input path is relative, start with a base path. - if (path_components[0].length() == 0) { + if (path_components[0].empty()) { std::vector<std::string> base_components; // Use the given base path. SystemTools::SplitPath(in_base, base_components); @@ -3272,7 +3253,7 @@ std::string SystemTools::CollapseFullPath(const std::string& in_path, SystemTools::CheckTranslationPath(newPath); #ifdef _WIN32 - newPath = SystemTools::GetActualCaseForPath(newPath); + newPath = SystemTools::GetActualCaseForPathCached(newPath); SystemTools::ConvertToUnixSlashes(newPath); #endif // Return the reconstructed path. @@ -3305,7 +3286,7 @@ std::string SystemTools::RelativePath(const std::string& local, unsigned int sameCount = 0; while (((sameCount <= (localSplit.size() - 1)) && (sameCount <= (remoteSplit.size() - 1))) && -// for windows and apple do a case insensitive string compare +// for Windows and Apple do a case insensitive string compare #if defined(_WIN32) || defined(__APPLE__) SystemTools::Strucmp(localSplit[sameCount].c_str(), remoteSplit[sameCount].c_str()) == 0 @@ -3430,6 +3411,13 @@ std::string SystemTools::GetActualCaseForPath(const std::string& p) #ifndef _WIN32 return p; #else + return GetCasePathName(p); +#endif +} + +#ifdef _WIN32 +std::string SystemTools::GetActualCaseForPathCached(std::string const& p) +{ // Check to see if actual case has already been called // for this path, and the result is stored in the PathCaseMap SystemToolsPathCaseMap::iterator i = SystemTools::PathCaseMap->find(p); @@ -3442,8 +3430,8 @@ std::string SystemTools::GetActualCaseForPath(const std::string& p) } (*SystemTools::PathCaseMap)[p] = casePath; return casePath; -#endif } +#endif const char* SystemTools::SplitPathRootComponent(const std::string& p, std::string* root) @@ -3595,7 +3583,7 @@ std::string SystemTools::JoinPath( // All remaining components are always separated with a slash. while (first != last) { - result.append("/"); + result.push_back('/'); result.append((*first++)); } @@ -3691,7 +3679,12 @@ std::string SystemTools::GetFilenamePath(const std::string& filename) */ std::string SystemTools::GetFilenameName(const std::string& filename) { - std::string::size_type slash_pos = filename.find_last_of("/\\"); +#if defined(_WIN32) || defined(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES) + const char* separators = "/\\"; +#else + char separators = '/'; +#endif + std::string::size_type slash_pos = filename.find_last_of(separators); if (slash_pos != std::string::npos) { return filename.substr(slash_pos + 1); } else { @@ -4219,11 +4212,16 @@ bool SystemTools::IsSubDirectory(const std::string& cSubdir, std::string dir = cDir; SystemTools::ConvertToUnixSlashes(subdir); SystemTools::ConvertToUnixSlashes(dir); - if (subdir.size() > dir.size() && subdir[dir.size()] == '/') { - std::string s = subdir.substr(0, dir.size()); - return SystemTools::ComparePath(s, dir); + if (subdir.size() <= dir.size() || dir.empty()) { + return false; } - return false; + bool isRootPath = *dir.rbegin() == '/'; // like "/" or "C:/" + size_t expectedSlashPosition = isRootPath ? dir.size() - 1u : dir.size(); + if (subdir[expectedSlashPosition] != '/') { + return false; + } + std::string s = subdir.substr(0, dir.size()); + return SystemTools::ComparePath(s, dir); } void SystemTools::Delay(unsigned int msec) diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in index 35bc1b1..e79e3fc 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 @@ -881,7 +881,7 @@ public: /** * Get the width of the terminal window. The code may or may not work, so - * make sure you have some resonable defaults prepared if the code returns + * make sure you have some reasonable defaults prepared if the code returns * some bogus size. */ static int GetTerminalWidth(); @@ -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); @@ -988,6 +988,7 @@ private: */ static SystemToolsTranslationMap* TranslationMap; #ifdef _WIN32 + static std::string GetActualCaseForPathCached(std::string const& path); static SystemToolsPathCaseMap* PathCaseMap; static SystemToolsEnvMap* EnvMap; #endif diff --git a/Source/kwsys/hash_map.hxx.in b/Source/kwsys/hash_map.hxx.in index 3f9174f..8c9b81e 100644 --- a/Source/kwsys/hash_map.hxx.in +++ b/Source/kwsys/hash_map.hxx.in @@ -49,7 +49,7 @@ namespace @KWSYS_NAMESPACE@ { // select1st is an extension: it is not part of the standard. template <class T1, class T2> -struct hash_select1st : public std::unary_function<std::pair<T1, T2>, T1> +struct hash_select1st { const T1& operator()(const std::pair<T1, T2>& __x) const { diff --git a/Source/kwsys/hash_set.hxx.in b/Source/kwsys/hash_set.hxx.in index e3a0c6c..5edd367 100644 --- a/Source/kwsys/hash_set.hxx.in +++ b/Source/kwsys/hash_set.hxx.in @@ -49,7 +49,7 @@ namespace @KWSYS_NAMESPACE@ { // identity is an extension: it is not part of the standard. template <class _Tp> -struct _Identity : public std::unary_function<_Tp, _Tp> +struct _Identity { const _Tp& operator()(const _Tp& __x) const { return __x; } }; diff --git a/Source/kwsys/hashtable.hxx.in b/Source/kwsys/hashtable.hxx.in index dd92cb9..e962f17 100644 --- a/Source/kwsys/hashtable.hxx.in +++ b/Source/kwsys/hashtable.hxx.in @@ -35,13 +35,12 @@ #include <@KWSYS_NAMESPACE@/Configure.hxx> -#include <algorithm> // lower_bound -#include <functional> // unary_function -#include <iterator> // iterator_traits -#include <memory> // allocator -#include <stddef.h> // size_t -#include <utility> // pair -#include <vector> // vector +#include <algorithm> // lower_bound +#include <iterator> // iterator_traits +#include <memory> // allocator +#include <stddef.h> // size_t +#include <utility> // pair +#include <vector> // vector #if defined(_MSC_VER) #pragma warning(push) 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/testCommandLineArguments.cxx b/Source/kwsys/testCommandLineArguments.cxx index d2215d6..78baed9 100644 --- a/Source/kwsys/testCommandLineArguments.cxx +++ b/Source/kwsys/testCommandLineArguments.cxx @@ -76,7 +76,7 @@ int testCommandLineArguments(int argc, char* argv[]) int some_int_variable = 10; double some_double_variable = 10.10; - char* some_string_variable = 0; + char* some_string_variable = KWSYS_NULLPTR; std::string some_stl_string_variable = ""; bool some_bool_variable = false; bool some_bool_variable1 = false; @@ -202,7 +202,7 @@ int testCommandLineArguments(int argc, char* argv[]) for (cc = 0; cc < strings_argument.size(); ++cc) { delete[] strings_argument[cc]; - strings_argument[cc] = 0; + strings_argument[cc] = KWSYS_NULLPTR; } return res; } diff --git a/Source/kwsys/testCommandLineArguments1.cxx b/Source/kwsys/testCommandLineArguments1.cxx index 5a03401..5dfa5e3 100644 --- a/Source/kwsys/testCommandLineArguments1.cxx +++ b/Source/kwsys/testCommandLineArguments1.cxx @@ -21,7 +21,7 @@ int testCommandLineArguments1(int argc, char* argv[]) arg.Initialize(argc, argv); int n = 0; - char* m = 0; + char* m = KWSYS_NULLPTR; std::string p; int res = 0; @@ -55,11 +55,11 @@ int testCommandLineArguments1(int argc, char* argv[]) delete[] m; } - char** newArgv = 0; + char** newArgv = KWSYS_NULLPTR; int newArgc = 0; arg.GetUnusedArguments(&newArgc, &newArgv); int cc; - const char* valid_unused_args[9] = { 0, + const char* valid_unused_args[9] = { KWSYS_NULLPTR, "--ignored", "--second-ignored", "third-ignored", 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..6bf273f 100644 --- a/Source/kwsys/testEncoding.cxx +++ b/Source/kwsys/testEncoding.cxx @@ -75,12 +75,16 @@ 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 std::wstring wstr = kwsys::Encoding::ToWide(cstr); - wstr = kwsys::Encoding::ToWide(NULL); + wstr = kwsys::Encoding::ToWide(KWSYS_NULLPTR); if (wstr != L"") { const wchar_t* wcstr = wstr.c_str(); std::cout << "ToWide(NULL) returned"; @@ -108,7 +112,7 @@ static int testRobustEncoding() std::string win_str = kwsys::Encoding::ToNarrow(cwstr); #endif - std::string str = kwsys::Encoding::ToNarrow(NULL); + std::string str = kwsys::Encoding::ToNarrow(KWSYS_NULLPTR); if (str != "") { std::cout << "ToNarrow(NULL) returned " << str << std::endl; ret++; @@ -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..e436a2b 100644 --- a/Source/kwsys/testSystemTools.cxx +++ b/Source/kwsys/testSystemTools.cxx @@ -39,20 +39,20 @@ typedef unsigned short mode_t; static const char* toUnixPaths[][2] = { { "/usr/local/bin/passwd", "/usr/local/bin/passwd" }, { "/usr/lo cal/bin/pa sswd", "/usr/lo cal/bin/pa sswd" }, - { "/usr/lo\\ cal/bin/pa\\ sswd", "/usr/lo\\ cal/bin/pa\\ sswd" }, + { "/usr/lo\\ cal/bin/pa\\ sswd", "/usr/lo/ cal/bin/pa/ sswd" }, { "c:/usr/local/bin/passwd", "c:/usr/local/bin/passwd" }, { "c:/usr/lo cal/bin/pa sswd", "c:/usr/lo cal/bin/pa sswd" }, - { "c:/usr/lo\\ cal/bin/pa\\ sswd", "c:/usr/lo\\ cal/bin/pa\\ sswd" }, + { "c:/usr/lo\\ cal/bin/pa\\ sswd", "c:/usr/lo/ cal/bin/pa/ sswd" }, { "\\usr\\local\\bin\\passwd", "/usr/local/bin/passwd" }, { "\\usr\\lo cal\\bin\\pa sswd", "/usr/lo cal/bin/pa sswd" }, - { "\\usr\\lo\\ cal\\bin\\pa\\ sswd", "/usr/lo\\ cal/bin/pa\\ sswd" }, + { "\\usr\\lo\\ cal\\bin\\pa\\ sswd", "/usr/lo/ cal/bin/pa/ sswd" }, { "c:\\usr\\local\\bin\\passwd", "c:/usr/local/bin/passwd" }, { "c:\\usr\\lo cal\\bin\\pa sswd", "c:/usr/lo cal/bin/pa sswd" }, - { "c:\\usr\\lo\\ cal\\bin\\pa\\ sswd", "c:/usr/lo\\ cal/bin/pa\\ sswd" }, + { "c:\\usr\\lo\\ cal\\bin\\pa\\ sswd", "c:/usr/lo/ cal/bin/pa/ sswd" }, { "\\\\usr\\local\\bin\\passwd", "//usr/local/bin/passwd" }, { "\\\\usr\\lo cal\\bin\\pa sswd", "//usr/lo cal/bin/pa sswd" }, - { "\\\\usr\\lo\\ cal\\bin\\pa\\ sswd", "//usr/lo\\ cal/bin/pa\\ sswd" }, - { 0, 0 } + { "\\\\usr\\lo\\ cal\\bin\\pa\\ sswd", "//usr/lo/ cal/bin/pa/ sswd" }, + { KWSYS_NULLPTR, KWSYS_NULLPTR } }; static bool CheckConvertToUnixSlashes(std::string const& input, @@ -68,10 +68,11 @@ static bool CheckConvertToUnixSlashes(std::string const& input, return true; } -static const char* checkEscapeChars[][4] = { { "1 foo 2 bar 2", "12", "\\", - "\\1 foo \\2 bar \\2" }, - { " {} ", "{}", "#", " #{#} " }, - { 0, 0, 0, 0 } }; +static const char* checkEscapeChars[][4] = { + { "1 foo 2 bar 2", "12", "\\", "\\1 foo \\2 bar \\2" }, + { " {} ", "{}", "#", " #{#} " }, + { KWSYS_NULLPTR, KWSYS_NULLPTR, KWSYS_NULLPTR, KWSYS_NULLPTR } +}; static bool CheckEscapeChars(std::string const& input, const char* chars_to_escape, char escape_char, @@ -159,7 +160,7 @@ static bool CheckFileOperations() res = false; } // calling with 0 pointer should return false - if (kwsys::SystemTools::MakeDirectory(0)) { + if (kwsys::SystemTools::MakeDirectory(KWSYS_NULLPTR)) { std::cerr << "Problem with MakeDirectory(0)" << std::endl; res = false; } @@ -217,11 +218,11 @@ static bool CheckFileOperations() } // calling with 0 pointer should return false - if (kwsys::SystemTools::FileExists(0)) { + if (kwsys::SystemTools::FileExists(KWSYS_NULLPTR)) { std::cerr << "Problem with FileExists(0)" << std::endl; res = false; } - if (kwsys::SystemTools::FileExists(0, true)) { + if (kwsys::SystemTools::FileExists(KWSYS_NULLPTR, true)) { std::cerr << "Problem with FileExists(0) as file" << std::endl; res = false; } @@ -254,22 +255,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 +286,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; } @@ -699,6 +700,16 @@ static bool CheckCollapsePath() bool res = true; res &= CheckCollapsePath("/usr/share/*", "/usr/share/*"); res &= CheckCollapsePath("C:/Windows/*", "C:/Windows/*"); + res &= CheckCollapsePath("/usr/share/../lib", "/usr/lib"); + res &= CheckCollapsePath("/usr/share/./lib", "/usr/share/lib"); + res &= CheckCollapsePath("/usr/share/../../lib", "/lib"); + res &= CheckCollapsePath("/usr/share/.././../lib", "/lib"); + res &= CheckCollapsePath("/../lib", "/lib"); + res &= CheckCollapsePath("/../lib/", "/lib"); + res &= CheckCollapsePath("/", "/"); + res &= CheckCollapsePath("C:/", "C:/"); + res &= CheckCollapsePath("C:/../", "C:/"); + res &= CheckCollapsePath("C:/../../", "C:/"); return res; } @@ -763,20 +774,26 @@ static bool CheckGetFilenameName() const char* windowsFilepath = "C:\\somewhere\\something"; const char* unixFilepath = "/somewhere/something"; - std::string expectedFilename = "something"; +#if defined(_WIN32) || defined(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES) + std::string expectedWindowsFilename = "something"; +#else + std::string expectedWindowsFilename = "C:\\somewhere\\something"; +#endif + std::string expectedUnixFilename = "something"; bool res = true; std::string filename = kwsys::SystemTools::GetFilenameName(windowsFilepath); - if (filename != expectedFilename) { + if (filename != expectedWindowsFilename) { std::cerr << "GetFilenameName(" << windowsFilepath << ") yielded " - << filename << " instead of " << expectedFilename << std::endl; + << filename << " instead of " << expectedWindowsFilename + << std::endl; res = false; } filename = kwsys::SystemTools::GetFilenameName(unixFilepath); - if (filename != expectedFilename) { + if (filename != expectedUnixFilename) { std::cerr << "GetFilenameName(" << unixFilepath << ") yielded " << filename - << " instead of " << expectedFilename << std::endl; + << " instead of " << expectedUnixFilename << std::endl; res = false; } return res; @@ -813,6 +830,39 @@ static bool CheckFind() return res; } +static bool CheckIsSubDirectory() +{ + bool res = true; + + if (kwsys::SystemTools::IsSubDirectory("/foo", "/") == false) { + std::cerr << "Problem with IsSubDirectory (root - unix): " << std::endl; + res = false; + } + if (kwsys::SystemTools::IsSubDirectory("c:/foo", "c:/") == false) { + std::cerr << "Problem with IsSubDirectory (root - dos): " << std::endl; + res = false; + } + if (kwsys::SystemTools::IsSubDirectory("/foo/bar", "/foo") == false) { + std::cerr << "Problem with IsSubDirectory (deep): " << std::endl; + res = false; + } + if (kwsys::SystemTools::IsSubDirectory("/foo", "/foo") == true) { + std::cerr << "Problem with IsSubDirectory (identity): " << std::endl; + res = false; + } + if (kwsys::SystemTools::IsSubDirectory("/fooo", "/foo") == true) { + std::cerr << "Problem with IsSubDirectory (substring): " << std::endl; + res = false; + } + if (kwsys::SystemTools::IsSubDirectory("/foo/", "/foo") == true) { + std::cerr << "Problem with IsSubDirectory (prepended slash): " + << std::endl; + res = false; + } + + return res; +} + static bool CheckGetLineFromStream() { const std::string fileWithFiveCharsOnFirstLine(TEST_SYSTEMTOOLS_SOURCE_DIR @@ -897,6 +947,8 @@ int testSystemTools(int, char* []) res &= CheckFind(); + res &= CheckIsSubDirectory(); + res &= CheckGetLineFromStream(); res &= CheckGetFilenameName(); |