diff options
Diffstat (limited to 'Source')
115 files changed, 2544 insertions, 1651 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index a0010a2..e547356 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -131,6 +131,8 @@ set(SRCS LexerParser/cmListFileLexer.c LexerParser/cmListFileLexer.in.l + cmAffinity.cxx + cmAffinity.h cmArchiveWrite.cxx cmBase32.cxx cmCacheManager.cxx diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 533d59f..0f1a352 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 11) -set(CMake_VERSION_PATCH 0) -#set(CMake_VERSION_RC 0) +set(CMake_VERSION_PATCH 20180404) +#set(CMake_VERSION_RC 1) diff --git a/Source/CMakeVersionCompute.cmake b/Source/CMakeVersionCompute.cmake index 79264ed..72a5800 100644 --- a/Source/CMakeVersionCompute.cmake +++ b/Source/CMakeVersionCompute.cmake @@ -32,7 +32,12 @@ endif() # 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}) + set(CMake_RCVERSION_YEAR "${CMAKE_MATCH_1}") + set(CMake_RCVERSION_MONTH_DAY "${CMAKE_MATCH_2}") + string(REGEX REPLACE "^0+" "" CMake_RCVERSION_MONTH_DAY "${CMake_RCVERSION_MONTH_DAY}") + set(CMake_RCVERSION ${CMake_VERSION_MAJOR},${CMake_VERSION_MINOR},${CMake_RCVERSION_YEAR},${CMake_RCVERSION_MONTH_DAY}) + unset(CMake_RCVERSION_MONTH_DAY) + unset(CMake_RCVERSION_YEAR) else() set(CMake_RCVERSION ${CMake_VERSION_MAJOR},${CMake_VERSION_MINOR},${CMake_VERSION_PATCH}) endif() diff --git a/Source/CPack/cmCPackArchiveGenerator.cxx b/Source/CPack/cmCPackArchiveGenerator.cxx index 9ff547a..00fbdab 100644 --- a/Source/CPack/cmCPackArchiveGenerator.cxx +++ b/Source/CPack/cmCPackArchiveGenerator.cxx @@ -9,6 +9,7 @@ #include "cmSystemTools.h" #include "cmWorkingDirectory.h" +#include <cstring> #include <ostream> #include <utility> #include <vector> @@ -51,6 +52,7 @@ int cmCPackArchiveGenerator::InitializeInternal() this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "1"); return this->Superclass::InitializeInternal(); } + int cmCPackArchiveGenerator::addOneComponentToArchive( cmArchiveWrite& archive, cmCPackComponent* component) { @@ -61,6 +63,13 @@ int cmCPackArchiveGenerator::addOneComponentToArchive( localToplevel += "/" + component->Name; // Change to local toplevel cmWorkingDirectory workdir(localToplevel); + if (workdir.Failed()) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Failed to change working directory to " + << localToplevel << " : " + << std::strerror(workdir.GetLastResult()) << std::endl); + return 0; + } std::string filePrefix; if (this->IsOn("CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY")) { filePrefix = this->GetOption("CPACK_PACKAGE_FILE_NAME"); @@ -237,6 +246,13 @@ int cmCPackArchiveGenerator::PackageFiles() // CASE 3 : NON COMPONENT package. DECLARE_AND_OPEN_ARCHIVE(packageFileNames[0], archive); cmWorkingDirectory workdir(toplevel); + if (workdir.Failed()) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Failed to change working directory to " + << toplevel << " : " + << std::strerror(workdir.GetLastResult()) << std::endl); + return 0; + } for (std::string const& file : files) { // Get the relative path to the file std::string rp = cmSystemTools::RelativePath(toplevel, file); diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx index d838b30..64aba10 100644 --- a/Source/CPack/cmCPackGenerator.cxx +++ b/Source/CPack/cmCPackGenerator.cxx @@ -6,6 +6,7 @@ #include "cmsys/Glob.hxx" #include "cmsys/RegularExpression.hxx" #include <algorithm> +#include <cstring> #include <memory> // IWYU pragma: keep #include <utility> @@ -404,6 +405,13 @@ int cmCPackGenerator::InstallProjectViaInstalledDirectories( cmCPackLogger(cmCPackLog::LOG_DEBUG, "Change dir to: " << goToDir << std::endl); cmWorkingDirectory workdir(goToDir); + if (workdir.Failed()) { + cmCPackLogger( + cmCPackLog::LOG_ERROR, "Failed to change working directory to " + << goToDir << " : " << std::strerror(workdir.GetLastResult()) + << std::endl); + return 0; + } for (auto const& symlinked : symlinkedFiles) { cmCPackLogger(cmCPackLog::LOG_DEBUG, "Will create a symlink: " << symlinked.second << "--> " << symlinked.first @@ -994,7 +1002,8 @@ int cmCPackGenerator::DoPackage() { // scope that enables package generators to run internal scripts with // latest CMake policies enabled cmMakefile::ScopePushPop pp{ this->MakefileMap }; - this->MakefileMap->SetPolicyVersion(cmVersion::GetCMakeVersion()); + this->MakefileMap->SetPolicyVersion(cmVersion::GetCMakeVersion(), + std::string()); if (!this->PackageFiles() || cmSystemTools::GetErrorOccuredFlag()) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem compressing the directory" diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx index 2e1ea4c..b2c68e7 100644 --- a/Source/CTest/cmCTestBuildAndTestHandler.cxx +++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx @@ -11,6 +11,7 @@ #include "cmsys/Process.h" #include <chrono> +#include <cstring> #include <ratio> #include <stdlib.h> @@ -196,6 +197,16 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) cmSystemTools::MakeDirectory(this->BinaryDir); } cmWorkingDirectory workdir(this->BinaryDir); + if (workdir.Failed()) { + auto msg = "Failed to change working directory to " + this->BinaryDir + + " : " + std::strerror(workdir.GetLastResult()) + "\n"; + if (outstring) { + *outstring = msg; + } else { + cmCTestLog(this->CTest, ERROR_MESSAGE, msg); + } + return 1; + } if (this->BuildNoCMake) { // Make the generator available for the Build call below. @@ -307,7 +318,16 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) // run the test from the this->BuildRunDir if set if (!this->BuildRunDir.empty()) { out << "Run test in directory: " << this->BuildRunDir << "\n"; - cmSystemTools::ChangeDirectory(this->BuildRunDir); + if (!workdir.SetDirectory(this->BuildRunDir)) { + out << "Failed to change working directory : " + << std::strerror(workdir.GetLastResult()) << "\n"; + if (outstring) { + *outstring = out.str(); + } else { + cmCTestLog(this->CTest, ERROR_MESSAGE, out.str()); + } + return 1; + } } out << "Running test command: \"" << fullPath << "\""; for (std::string const& testCommandArg : this->TestCommandArgs) { diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index 9c66e73..bafbe9a 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -23,6 +23,7 @@ #include "cmsys/RegularExpression.hxx" #include <algorithm> #include <chrono> +#include <cstring> #include <iomanip> #include <iterator> #include <sstream> @@ -927,7 +928,8 @@ int cmCTestCoverageHandler::HandleGCovCoverage( std::string gcovCommand = this->CTest->GetCTestConfiguration("CoverageCommand"); if (gcovCommand.empty()) { - cmCTestLog(this->CTest, WARNING, "Could not find gcov." << std::endl); + cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, + "Could not find gcov." << std::endl, this->Quiet); return 0; } std::string gcovExtraFlags = @@ -975,7 +977,12 @@ int cmCTestCoverageHandler::HandleGCovCoverage( std::string testingDir = this->CTest->GetBinaryDir() + "/Testing"; std::string tempDir = testingDir + "/CoverageInfo"; - cmSystemTools::MakeDirectory(tempDir); + if (!cmSystemTools::MakeDirectory(tempDir)) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Unable to make directory: " << tempDir << std::endl); + cont->Error++; + return 0; + } cmWorkingDirectory workdir(tempDir); int gcovStyle = 0; @@ -1376,6 +1383,14 @@ int cmCTestCoverageHandler::HandleLCovCoverage( this->Quiet); std::string fileDir = cmSystemTools::GetFilenamePath(f); cmWorkingDirectory workdir(fileDir); + if (workdir.Failed()) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Unable to change working directory to " + << fileDir << " : " + << std::strerror(workdir.GetLastResult()) << std::endl); + cont->Error++; + continue; + } cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Current coverage dir: " << fileDir << std::endl, @@ -1600,6 +1615,12 @@ bool cmCTestCoverageHandler::FindLCovFiles(std::vector<std::string>& files) gl.RecurseThroughSymlinksOff(); std::string buildDir = this->CTest->GetCTestConfiguration("BuildDirectory"); cmWorkingDirectory workdir(buildDir); + if (workdir.Failed()) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Unable to change working directory to " << buildDir + << std::endl); + return false; + } // Run profmerge to merge all *.dyn files into dpi files if (!cmSystemTools::RunSingleCommand("profmerge")) { diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx index 5a7baf5..1fff2fa 100644 --- a/Source/CTest/cmCTestHandlerCommand.cxx +++ b/Source/CTest/cmCTestHandlerCommand.cxx @@ -9,6 +9,7 @@ #include "cmWorkingDirectory.h" #include "cmake.h" +#include <cstring> #include <sstream> #include <stdlib.h> @@ -218,6 +219,21 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, } cmWorkingDirectory workdir( this->CTest->GetCTestConfiguration("BuildDirectory")); + if (workdir.Failed()) { + this->SetError("failed to change directory to " + + this->CTest->GetCTestConfiguration("BuildDirectory") + + " : " + std::strerror(workdir.GetLastResult())); + if (capureCMakeError) { + this->Makefile->AddDefinition(this->Values[ct_CAPTURE_CMAKE_ERROR], + "-1"); + cmCTestLog(this->CTest, ERROR_MESSAGE, this->GetName() + << " " << this->GetError() << "\n"); + // return success because failure is recorded in CAPTURE_CMAKE_ERROR + return true; + } + return false; + } + int res = handler->ProcessHandler(); if (this->Values[ct_RETURN_VALUE] && *this->Values[ct_RETURN_VALUE]) { std::ostringstream str; diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index 50c2d86..14b5caa 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCTestMultiProcessHandler.h" +#include "cmAffinity.h" #include "cmCTest.h" #include "cmCTestRunTest.h" #include "cmCTestScriptHandler.h" @@ -19,6 +20,7 @@ #include <algorithm> #include <chrono> +#include <cstring> #include <iomanip> #include <list> #include <math.h> @@ -53,6 +55,8 @@ cmCTestMultiProcessHandler::cmCTestMultiProcessHandler() this->TestLoad = 0; this->Completed = 0; this->RunningCount = 0; + this->ProcessorsAvailable = cmAffinity::GetProcessorsAvailable(); + this->HaveAffinity = this->ProcessorsAvailable.size(); this->StopTimePassed = false; this->HasCycles = false; this->SerialTestRunning = false; @@ -127,6 +131,21 @@ bool cmCTestMultiProcessHandler::StartTestProcess(int test) return false; } + if (this->HaveAffinity && this->Properties[test]->WantAffinity) { + size_t needProcessors = this->GetProcessorsUsed(test); + if (needProcessors > this->ProcessorsAvailable.size()) { + return false; + } + std::vector<size_t> affinity; + affinity.reserve(needProcessors); + for (size_t i = 0; i < needProcessors; ++i) { + auto p = this->ProcessorsAvailable.begin(); + affinity.push_back(*p); + this->ProcessorsAvailable.erase(p); + } + this->Properties[test]->Affinity = std::move(affinity); + } + cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "test " << test << "\n", this->Quiet); this->TestRunningMap[test] = true; // mark the test as running @@ -151,13 +170,19 @@ bool cmCTestMultiProcessHandler::StartTestProcess(int test) } } - cmWorkingDirectory workdir(this->Properties[test]->Directory); - - // Lock the resources we'll be using + // Always lock the resources we'll be using, even if we fail to set the + // working directory because FinishTestProcess() will try to unlock them this->LockResources(test); - if (testRun->StartTest(this->Total)) { - return true; + cmWorkingDirectory workdir(this->Properties[test]->Directory); + if (workdir.Failed()) { + testRun->StartFailure("Failed to change working directory to " + + this->Properties[test]->Directory + " : " + + std::strerror(workdir.GetLastResult())); + } else { + if (testRun->StartTest(this->Total)) { + return true; + } } this->FinishTestProcess(testRun, false); @@ -200,6 +225,11 @@ inline size_t cmCTestMultiProcessHandler::GetProcessorsUsed(int test) if (processors > this->ParallelLevel) { processors = this->ParallelLevel; } + // Cap tests that want affinity to the maximum affinity available. + if (this->HaveAffinity && processors > this->HaveAffinity && + this->Properties[test]->WantAffinity) { + processors = this->HaveAffinity; + } return processors; } @@ -398,6 +428,11 @@ void cmCTestMultiProcessHandler::FinishTestProcess(cmCTestRunTest* runner, this->UnlockResources(test); this->RunningCount -= GetProcessorsUsed(test); + for (auto p : properties->Affinity) { + this->ProcessorsAvailable.insert(p); + } + properties->Affinity.clear(); + delete runner; if (started) { this->StartNextTests(); @@ -666,6 +701,8 @@ void cmCTestMultiProcessHandler::PrintTestList() count++; cmCTestTestHandler::cmCTestTestProperties& p = *it.second; + // Don't worry if this fails, we are only showing the test list, not + // running the tests cmWorkingDirectory workdir(p.Directory); cmCTestRunTest testRun(*this); diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h index 7837ff9..19e1a35 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.h +++ b/Source/CTest/cmCTestMultiProcessHandler.h @@ -119,6 +119,8 @@ protected: // Number of tests that are complete size_t Completed; size_t RunningCount; + std::set<size_t> ProcessorsAvailable; + size_t HaveAffinity; bool StopTimePassed; // list of test properties (indices concurrent to the test map) PropertiesMap Properties; diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index 30ad38c..8d8ebaa 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -14,6 +14,7 @@ #include "cmsys/RegularExpression.hxx" #include <chrono> #include <cmAlgorithms.h> +#include <cstring> #include <iomanip> #include <ratio> #include <sstream> @@ -248,11 +249,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) *this->TestHandler->LogFile << "Test time = " << buf << std::endl; } - // Set the working directory to the tests directory to process Dart files. - { - cmWorkingDirectory workdir(this->TestProperties->Directory); - this->DartProcessing(); - } + this->DartProcessing(); // if this is doing MemCheck then all the output needs to be put into // Output since that is what is parsed by cmCTestMemCheckHandler @@ -338,6 +335,13 @@ bool cmCTestRunTest::StartAgain() this->RunAgain = false; // reset // change to tests directory cmWorkingDirectory workdir(this->TestProperties->Directory); + if (workdir.Failed()) { + this->StartFailure("Failed to change working directory to " + + this->TestProperties->Directory + " : " + + std::strerror(workdir.GetLastResult())); + return true; + } + this->StartTest(this->TotalNumberOfTests); return true; } @@ -386,6 +390,37 @@ void cmCTestRunTest::MemCheckPostProcess() handler->PostProcessTest(this->TestResult, this->Index); } +void cmCTestRunTest::StartFailure(std::string const& output) +{ + // Still need to log the Start message so the test summary records our + // attempt to start this test + cmCTestLog(this->CTest, HANDLER_OUTPUT, + std::setw(2 * getNumWidth(this->TotalNumberOfTests) + 8) + << "Start " + << std::setw(getNumWidth(this->TestHandler->GetMaxIndex())) + << this->TestProperties->Index << ": " + << this->TestProperties->Name << std::endl); + + this->ProcessOutput.clear(); + if (!output.empty()) { + *this->TestHandler->LogFile << output << std::endl; + cmCTestLog(this->CTest, ERROR_MESSAGE, output << std::endl); + } + + this->TestResult.Properties = this->TestProperties; + this->TestResult.ExecutionTime = cmDuration::zero(); + this->TestResult.CompressOutput = false; + this->TestResult.ReturnValue = -1; + this->TestResult.CompletionStatus = "Failed to start"; + this->TestResult.Status = cmCTestTestHandler::NOT_RUN; + this->TestResult.TestCount = this->TestProperties->Index; + this->TestResult.Name = this->TestProperties->Name; + this->TestResult.Path = this->TestProperties->Directory; + this->TestResult.Output = output; + this->TestResult.FullCommandLine.clear(); + this->TestProcess = cm::make_unique<cmProcess>(*this); +} + // Starts the execution of a test. Returns once it has started bool cmCTestRunTest::StartTest(size_t total) { @@ -515,7 +550,8 @@ bool cmCTestRunTest::StartTest(size_t total) } return this->ForkProcess(timeout, this->TestProperties->ExplicitTimeout, - &this->TestProperties->Environment); + &this->TestProperties->Environment, + &this->TestProperties->Affinity); } void cmCTestRunTest::ComputeArguments() @@ -591,7 +627,8 @@ void cmCTestRunTest::DartProcessing() } bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout, - std::vector<std::string>* environment) + std::vector<std::string>* environment, + std::vector<size_t>* affinity) { this->TestProcess = cm::make_unique<cmProcess>(*this); this->TestProcess->SetId(this->Index); @@ -637,7 +674,8 @@ bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout, cmSystemTools::AppendEnv(*environment); } - return this->TestProcess->StartProcess(this->MultiTestHandler.Loop); + return this->TestProcess->StartProcess(this->MultiTestHandler.Loop, + affinity); } void cmCTestRunTest::WriteLogOutputTop(size_t completed, size_t total) diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h index 4d57357..3b1d674 100644 --- a/Source/CTest/cmCTestRunTest.h +++ b/Source/CTest/cmCTestRunTest.h @@ -74,6 +74,8 @@ public: bool StartAgain(); + void StartFailure(std::string const& output); + cmCTest* GetCTest() const { return this->CTest; } void FinalizeTest(); @@ -83,7 +85,8 @@ private: void DartProcessing(); void ExeNotFound(std::string exe); bool ForkProcess(cmDuration testTimeOut, bool explicitTimeout, - std::vector<std::string>* environment); + std::vector<std::string>* environment, + std::vector<size_t>* affinity); void WriteLogOutputTop(size_t completed, size_t total); // Run post processing of the process output for MemCheck void MemCheckPostProcess(); diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx index e0bffd4..5fff730 100644 --- a/Source/CTest/cmCTestScriptHandler.cxx +++ b/Source/CTest/cmCTestScriptHandler.cxx @@ -527,7 +527,7 @@ int cmCTestScriptHandler::RunConfigurationScript( return result; } - // only run the curent script if we should + // only run the current script if we should if (this->Makefile && this->Makefile->IsOn("CTEST_RUN_CURRENT_SCRIPT") && this->ShouldRunCurrentScript) { return this->RunCurrentScript(); diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index 08d05c8..3bab81e 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -7,6 +7,7 @@ #include "cm_jsoncpp_value.h" #include "cmsys/Process.h" #include <chrono> +#include <cstring> #include <sstream> #include <stdio.h> #include <stdlib.h> @@ -1532,6 +1533,15 @@ int cmCTestSubmitHandler::ProcessHandler() // change to the build directory so that we can uses a relative path // on windows since scp doesn't support "c:" a drive in the path cmWorkingDirectory workdir(buildDirectory); + if (workdir.Failed()) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + " Failed to change directory to " + << buildDirectory << " : " + << std::strerror(workdir.GetLastResult()) << std::endl); + ofs << " Failed to change directory to " << buildDirectory << " : " + << std::strerror(workdir.GetLastResult()) << std::endl; + return -1; + } if (!this->SubmitUsingSCP(this->CTest->GetCTestConfiguration("ScpCommand"), "Testing/" + this->CTest->GetCurrentTag(), files, @@ -1551,6 +1561,15 @@ int cmCTestSubmitHandler::ProcessHandler() // change to the build directory so that we can uses a relative path // on windows since scp doesn't support "c:" a drive in the path cmWorkingDirectory workdir(buildDirectory); + if (workdir.Failed()) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + " Failed to change directory to " + << buildDirectory << " : " + << std::strerror(workdir.GetLastResult()) << std::endl); + ofs << " Failed to change directory to " << buildDirectory << " : " + << std::strerror(workdir.GetLastResult()) << std::endl; + return -1; + } cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Change directory: " << buildDirectory << std::endl, this->Quiet); diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index 84d8926..cbaf984 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -6,6 +6,7 @@ #include <cmsys/Base64.h> #include <cmsys/Directory.hxx> #include <cmsys/RegularExpression.hxx> +#include <cstring> #include <functional> #include <iomanip> #include <iterator> @@ -14,7 +15,6 @@ #include <sstream> #include <stdio.h> #include <stdlib.h> -#include <string.h> #include <time.h> #include "cmAlgorithms.h" @@ -85,6 +85,11 @@ bool cmCTestSubdirCommand::InitialPass(std::vector<std::string> const& args, bool readit = false; { cmWorkingDirectory workdir(fname); + if (workdir.Failed()) { + this->SetError("Failed to change directory to " + fname + " : " + + std::strerror(workdir.GetLastResult())); + return false; + } const char* testFilename; if (cmSystemTools::FileExists("CTestTestfile.cmake")) { // does the CTestTestfile.cmake exist ? @@ -2165,6 +2170,9 @@ bool cmCTestTestHandler::SetTestsProperties( rt.Processors = 1; } } + if (key == "PROCESSOR_AFFINITY") { + rt.WantAffinity = cmSystemTools::IsOn(val.c_str()); + } if (key == "SKIP_RETURN_CODE") { rt.SkipReturnCode = atoi(val.c_str()); if (rt.SkipReturnCode < 0 || rt.SkipReturnCode > 255) { @@ -2336,6 +2344,7 @@ bool cmCTestTestHandler::AddTest(const std::vector<std::string>& args) test.ExplicitTimeout = false; test.Cost = 0; test.Processors = 1; + test.WantAffinity = false; test.SkipReturnCode = -1; test.PreviousRuns = 0; if (this->UseIncludeRegExpFlag && diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index f4978b6..d2694a1 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -130,6 +130,8 @@ public: int Index; // Requested number of process slots int Processors; + bool WantAffinity; + std::vector<size_t> Affinity; // return code of test which will mark test as "not run" int SkipReturnCode; std::vector<std::string> Environment; diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx index 09ed0a9..5c9b169 100644 --- a/Source/CTest/cmProcess.cxx +++ b/Source/CTest/cmProcess.cxx @@ -83,7 +83,7 @@ void cmProcess::SetCommandArguments(std::vector<std::string> const& args) this->Arguments = args; } -bool cmProcess::StartProcess(uv_loop_t& loop) +bool cmProcess::StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity) { this->ProcessState = cmProcess::State::Error; if (this->Command.empty()) { @@ -138,6 +138,22 @@ bool cmProcess::StartProcess(uv_loop_t& loop) options.stdio_count = 3; // in, out and err options.exit_cb = &cmProcess::OnExitCB; options.stdio = stdio; +#if !defined(CMAKE_USE_SYSTEM_LIBUV) + std::vector<char> cpumask; + if (affinity && !affinity->empty()) { + cpumask.resize(static_cast<size_t>(uv_cpumask_size()), 0); + for (auto p : *affinity) { + cpumask[p] = 1; + } + options.cpumask = cpumask.data(); + options.cpumask_size = cpumask.size(); + } else { + options.cpumask = nullptr; + options.cpumask_size = 0; + } +#else + static_cast<void>(affinity); +#endif status = uv_read_start(pipe_reader, &cmProcess::OnAllocateCB, &cmProcess::OnReadCB); diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h index 20e24b9..b2d87fa 100644 --- a/Source/CTest/cmProcess.h +++ b/Source/CTest/cmProcess.h @@ -36,7 +36,7 @@ public: void ChangeTimeout(cmDuration t); void ResetStartTime(); // Return true if the process starts - bool StartProcess(uv_loop_t& loop); + bool StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity); enum class State { diff --git a/Source/Checks/Curses.cmake b/Source/Checks/Curses.cmake new file mode 100644 index 0000000..46dc770 --- /dev/null +++ b/Source/Checks/Curses.cmake @@ -0,0 +1,41 @@ +message(STATUS "Checking for curses support") + +# Try compiling a simple project using curses. +# Pass in any cache entries that the user may have set. +set(CMakeCheckCurses_ARGS "") +foreach(v + CURSES_INCLUDE_PATH + CURSES_CURSES_LIBRARY + CURSES_NCURSES_LIBRARY + CURSES_EXTRA_LIBRARY + CURSES_FORM_LIBRARY + ) + if(${v}) + list(APPEND CMakeCheckCurses_ARGS -D${v}=${${v}}) + endif() +endforeach() +file(REMOVE_RECURSE "${CMake_BINARY_DIR}/Source/Checks/Curses-build") +try_compile(CMakeCheckCurses_COMPILED + ${CMake_BINARY_DIR}/Source/Checks/Curses-build + ${CMake_SOURCE_DIR}/Source/Checks/Curses + CheckCurses # project name + CheckCurses # target name + CMAKE_FLAGS + "-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS}" + ${CMakeCheckCurses_ARGS} + OUTPUT_VARIABLE CMakeCheckCurses_OUTPUT + ) + +# Covnert result from cache entry to normal variable. +set(CMakeCheckCurses_COMPILED "${CMakeCheckCurses_COMPILED}") +unset(CMakeCheckCurses_COMPILED CACHE) + +if(CMakeCheckCurses_COMPILED) + message(STATUS "Checking for curses support - Success") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Checking for curses support passed with the following output:\n${CMakeCheckCurses_OUTPUT}\n\n") +else() + message(STATUS "Checking for curses support - Failed") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Checking for curses support failed with the following output:\n${CMakeCheckCurses_OUTPUT}\n\n") +endif() diff --git a/Source/Checks/Curses/CMakeLists.txt b/Source/Checks/Curses/CMakeLists.txt new file mode 100644 index 0000000..17318a3 --- /dev/null +++ b/Source/Checks/Curses/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.1) +if(POLICY CMP0060) + cmake_policy(SET CMP0060 NEW) +endif() +project(CheckCurses C) + +set(CURSES_NEED_NCURSES TRUE) +find_package(Curses) +if(NOT CURSES_FOUND) + return() +endif() +include_directories(${CURSES_INCLUDE_DIRS}) +add_executable(CheckCurses CheckCurses.c) +target_link_libraries(CheckCurses ${CURSES_LIBRARIES}) + +foreach(h + CURSES_HAVE_CURSES_H + CURSES_HAVE_NCURSES_H + CURSES_HAVE_NCURSES_NCURSES_H + CURSES_HAVE_NCURSES_CURSES_H + ) + if(${h}) + target_compile_definitions(CheckCurses PRIVATE ${h}) + endif() +endforeach() diff --git a/Source/Checks/Curses/CheckCurses.c b/Source/Checks/Curses/CheckCurses.c new file mode 100644 index 0000000..857ae28 --- /dev/null +++ b/Source/Checks/Curses/CheckCurses.c @@ -0,0 +1,15 @@ +#if defined(CURSES_HAVE_NCURSES_H) +#include <ncurses.h> +#elif defined(CURSES_HAVE_NCURSES_NCURSES_H) +#include <ncurses/ncurses.h> +#elif defined(CURSES_HAVE_NCURSES_CURSES_H) +#include <ncurses/curses.h> +#else +#include <curses.h> +#endif + +int main() +{ + curses_version(); + return 0; +} diff --git a/Source/CursesDialog/cmCursesStandardIncludes.h b/Source/CursesDialog/cmCursesStandardIncludes.h index 332d2af..60bad94 100644 --- a/Source/CursesDialog/cmCursesStandardIncludes.h +++ b/Source/CursesDialog/cmCursesStandardIncludes.h @@ -5,6 +5,11 @@ #include "cmConfigure.h" // IWYU pragma: keep +// Record whether __attribute__ is currently defined. See purpose below. +#ifndef __attribute__ +#define cm_no__attribute__ +#endif + #if defined(__hpux) #define _BOOL_DEFINED #include <sys/time.h> @@ -29,4 +34,12 @@ inline void curses_clear() #undef erase #undef clear +// The curses headers on some platforms (e.g. Solaris) may +// define __attribute__ as a macro. This breaks C++ headers +// in some cases, so undefine it now. +#if defined(cm_no__attribute__) && defined(__attribute__) +#undef __attribute__ +#endif +#undef cm_no__attribute__ + #endif // cmCursesStandardIncludes_h diff --git a/Source/cmAffinity.cxx b/Source/cmAffinity.cxx new file mode 100644 index 0000000..bdf1f42 --- /dev/null +++ b/Source/cmAffinity.cxx @@ -0,0 +1,62 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmAffinity.h" + +#include "cm_uv.h" + +#ifndef CMAKE_USE_SYSTEM_LIBUV +#ifdef _WIN32 +#define CM_HAVE_CPU_AFFINITY +#include <windows.h> +#elif defined(__linux__) || defined(__FreeBSD__) +#define CM_HAVE_CPU_AFFINITY +#include <pthread.h> +#include <sched.h> +#if defined(__FreeBSD__) +#include <pthread_np.h> +#include <sys/cpuset.h> +#include <sys/param.h> +#endif +#if defined(__linux__) +typedef cpu_set_t cm_cpuset_t; +#else +typedef cpuset_t cm_cpuset_t; +#endif +#endif +#endif + +namespace cmAffinity { + +std::set<size_t> GetProcessorsAvailable() +{ + std::set<size_t> processorsAvailable; +#ifdef CM_HAVE_CPU_AFFINITY + int cpumask_size = uv_cpumask_size(); + if (cpumask_size > 0) { +#ifdef _WIN32 + DWORD_PTR procmask; + DWORD_PTR sysmask; + if (GetProcessAffinityMask(GetCurrentProcess(), &procmask, &sysmask) != + 0) { + for (int i = 0; i < cpumask_size; ++i) { + if (procmask & (((DWORD_PTR)1) << i)) { + processorsAvailable.insert(i); + } + } + } +#else + cm_cpuset_t cpuset; + CPU_ZERO(&cpuset); // NOLINT(clang-tidy) + if (pthread_getaffinity_np(pthread_self(), sizeof(cpuset), &cpuset) == 0) { + for (int i = 0; i < cpumask_size; ++i) { + if (CPU_ISSET(i, &cpuset)) { + processorsAvailable.insert(i); + } + } + } +#endif + } +#endif + return processorsAvailable; +} +} diff --git a/Source/cmAffinity.h b/Source/cmAffinity.h new file mode 100644 index 0000000..3775bae --- /dev/null +++ b/Source/cmAffinity.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. */ +#pragma once +#include "cmConfigure.h" // IWYU pragma: keep + +#include <cstddef> +#include <set> + +namespace cmAffinity { + +std::set<size_t> GetProcessorsAvailable(); +} diff --git a/Source/cmCMakeMinimumRequired.cxx b/Source/cmCMakeMinimumRequired.cxx index bcc41fc..2b51976 100644 --- a/Source/cmCMakeMinimumRequired.cxx +++ b/Source/cmCMakeMinimumRequired.cxx @@ -42,12 +42,27 @@ bool cmCMakeMinimumRequired::InitialPass(std::vector<std::string> const& args, // Make sure there was a version to check. if (version_string.empty()) { - return this->EnforceUnknownArguments(); + return this->EnforceUnknownArguments(std::string()); + } + + // Separate the <min> version and any trailing ...<max> component. + std::string::size_type const dd = version_string.find("..."); + std::string const version_min = version_string.substr(0, dd); + std::string const version_max = dd != std::string::npos + ? version_string.substr(dd + 3, std::string::npos) + : std::string(); + if (dd != std::string::npos && + (version_min.empty() || version_max.empty())) { + std::ostringstream e; + e << "VERSION \"" << version_string + << "\" does not have a version on both sides of \"...\"."; + this->SetError(e.str()); + return false; } // Save the required version string. this->Makefile->AddDefinition("CMAKE_MINIMUM_REQUIRED_VERSION", - version_string.c_str()); + version_min.c_str()); // Get the current version number. unsigned int current_major = cmVersion::GetMajorVersion(); @@ -61,10 +76,10 @@ bool cmCMakeMinimumRequired::InitialPass(std::vector<std::string> const& args, unsigned int required_minor = 0; unsigned int required_patch = 0; unsigned int required_tweak = 0; - if (sscanf(version_string.c_str(), "%u.%u.%u.%u", &required_major, + if (sscanf(version_min.c_str(), "%u.%u.%u.%u", &required_major, &required_minor, &required_patch, &required_tweak) < 2) { std::ostringstream e; - e << "could not parse VERSION \"" << version_string << "\"."; + e << "could not parse VERSION \"" << version_min << "\"."; this->SetError(e.str()); return false; } @@ -78,7 +93,7 @@ bool cmCMakeMinimumRequired::InitialPass(std::vector<std::string> const& args, current_patch == required_patch && current_tweak < required_tweak)) { // The current version is too low. std::ostringstream e; - e << "CMake " << version_string + e << "CMake " << version_min << " or higher is required. You are running version " << cmVersion::GetCMakeVersion(); this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); @@ -87,7 +102,7 @@ bool cmCMakeMinimumRequired::InitialPass(std::vector<std::string> const& args, } // The version is not from the future, so enforce unknown arguments. - if (!this->EnforceUnknownArguments()) { + if (!this->EnforceUnknownArguments(version_max)) { return false; } @@ -95,22 +110,47 @@ bool cmCMakeMinimumRequired::InitialPass(std::vector<std::string> const& args, this->Makefile->IssueMessage( cmake::AUTHOR_WARNING, "Compatibility with CMake < 2.4 is not supported by CMake >= 3.0."); - this->Makefile->SetPolicyVersion("2.4"); + this->Makefile->SetPolicyVersion("2.4", version_max); } else { - this->Makefile->SetPolicyVersion(version_string.c_str()); + this->Makefile->SetPolicyVersion(version_min, version_max); } return true; } -bool cmCMakeMinimumRequired::EnforceUnknownArguments() +bool cmCMakeMinimumRequired::EnforceUnknownArguments( + std::string const& version_max) { - if (!this->UnknownArguments.empty()) { - std::ostringstream e; - e << "called with unknown argument \"" << this->UnknownArguments[0] - << "\"."; - this->SetError(e.str()); - return false; + if (this->UnknownArguments.empty()) { + return true; } - return true; + + // Consider the max version if at least two components were given. + unsigned int max_major = 0; + unsigned int max_minor = 0; + unsigned int max_patch = 0; + unsigned int max_tweak = 0; + if (sscanf(version_max.c_str(), "%u.%u.%u.%u", &max_major, &max_minor, + &max_patch, &max_tweak) >= 2) { + unsigned int current_major = cmVersion::GetMajorVersion(); + unsigned int current_minor = cmVersion::GetMinorVersion(); + unsigned int current_patch = cmVersion::GetPatchVersion(); + unsigned int current_tweak = cmVersion::GetTweakVersion(); + + if ((current_major < max_major) || + (current_major == max_major && current_minor < max_minor) || + (current_major == max_major && current_minor == max_minor && + current_patch < max_patch) || + (current_major == max_major && current_minor == max_minor && + current_patch == max_patch && current_tweak < max_tweak)) { + // A ...<max> version was given that is larger than the current + // version of CMake, so tolerate unknown arguments. + return true; + } + } + + std::ostringstream e; + e << "called with unknown argument \"" << this->UnknownArguments[0] << "\"."; + this->SetError(e.str()); + return false; } diff --git a/Source/cmCMakeMinimumRequired.h b/Source/cmCMakeMinimumRequired.h index 18d9460..f9b61e1 100644 --- a/Source/cmCMakeMinimumRequired.h +++ b/Source/cmCMakeMinimumRequired.h @@ -34,7 +34,7 @@ public: private: std::vector<std::string> UnknownArguments; - bool EnforceUnknownArguments(); + bool EnforceUnknownArguments(std::string const& version_max); }; #endif diff --git a/Source/cmCMakePolicyCommand.cxx b/Source/cmCMakePolicyCommand.cxx index 3ccc815..7ca1cbc 100644 --- a/Source/cmCMakePolicyCommand.cxx +++ b/Source/cmCMakePolicyCommand.cxx @@ -156,6 +156,23 @@ bool cmCMakePolicyCommand::HandleVersionMode( this->SetError("VERSION given too many arguments"); return false; } - this->Makefile->SetPolicyVersion(args[1].c_str()); + std::string const& version_string = args[1]; + + // Separate the <min> version and any trailing ...<max> component. + std::string::size_type const dd = version_string.find("..."); + std::string const version_min = version_string.substr(0, dd); + std::string const version_max = dd != std::string::npos + ? version_string.substr(dd + 3, std::string::npos) + : std::string(); + if (dd != std::string::npos && + (version_min.empty() || version_max.empty())) { + std::ostringstream e; + e << "VERSION \"" << version_string + << "\" does not have a version on both sides of \"...\"."; + this->SetError(e.str()); + return false; + } + + this->Makefile->SetPolicyVersion(version_min, version_max); return true; } diff --git a/Source/cmCTest.h b/Source/cmCTest.h index 673a40e..b2f4f25 100644 --- a/Source/cmCTest.h +++ b/Source/cmCTest.h @@ -347,7 +347,7 @@ public: const std::string& cmake_var, bool suppress = false); - /** Make string safe to be send as an URL */ + /** Make string safe to be sent as a URL */ static std::string MakeURLSafe(const std::string&); /** Decode a URL to the original string. */ diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx index fab2445..85ac985 100644 --- a/Source/cmCacheManager.cxx +++ b/Source/cmCacheManager.cxx @@ -160,14 +160,14 @@ bool cmCacheManager::LoadCache(const std::string& path, bool internal, currentcwd += "/CMakeCache.txt"; oldcwd += "/CMakeCache.txt"; if (!cmSystemTools::SameFile(oldcwd, currentcwd)) { - std::string message = - std::string("The current CMakeCache.txt directory ") + currentcwd + - std::string(" is different than the directory ") + - std::string(this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR")) + - std::string(" where CMakeCache.txt was created. This may result " - "in binaries being created in the wrong place. If you " - "are not sure, reedit the CMakeCache.txt"); - cmSystemTools::Error(message.c_str()); + std::ostringstream message; + message << "The current CMakeCache.txt directory " << currentcwd + << " is different than the directory " + << this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR") + << " where CMakeCache.txt was created. This may result " + "in binaries being created in the wrong place. If you " + "are not sure, reedit the CMakeCache.txt"; + cmSystemTools::Error(message.str().c_str()); } } return true; diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 8a5a6de..6e6e0be 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -240,21 +240,19 @@ because this need be done only for shared libraries without soname-s. cmComputeLinkInformation::cmComputeLinkInformation( const cmGeneratorTarget* target, const std::string& config) -{ // Store context information. - this->Target = target; - this->Makefile = this->Target->Target->GetMakefile(); - this->GlobalGenerator = - this->Target->GetLocalGenerator()->GetGlobalGenerator(); - this->CMakeInstance = this->GlobalGenerator->GetCMakeInstance(); - + : Target(target), + Makefile(target->Target->GetMakefile()), + GlobalGenerator(target->GetLocalGenerator()->GetGlobalGenerator()), + CMakeInstance(this->GlobalGenerator->GetCMakeInstance()) + // The configuration being linked. + , + Config(config) +{ // Check whether to recognize OpenBSD-style library versioned names. this->OpenBSD = this->Makefile->GetState()->GetGlobalPropertyAsBool( "FIND_LIBRARY_USE_OPENBSD_VERSIONING"); - // The configuration being linked. - this->Config = config; - // Allocate internals. this->OrderLinkerSearchPath = new cmOrderDirectories( this->GlobalGenerator, target, "linker search path"); @@ -406,17 +404,18 @@ cmComputeLinkInformation::~cmComputeLinkInformation() } cmComputeLinkInformation::ItemVector const& -cmComputeLinkInformation::GetItems() +cmComputeLinkInformation::GetItems() const { return this->Items; } std::vector<std::string> const& cmComputeLinkInformation::GetDirectories() + const { return this->OrderLinkerSearchPath->GetOrderedDirectories(); } -std::string cmComputeLinkInformation::GetRPathLinkString() +std::string cmComputeLinkInformation::GetRPathLinkString() const { // If there is no separate linker runtime search flag (-rpath-link) // there is no reason to compute a string. @@ -428,18 +427,19 @@ std::string cmComputeLinkInformation::GetRPathLinkString() return cmJoin(this->OrderDependentRPath->GetOrderedDirectories(), ":"); } -std::vector<std::string> const& cmComputeLinkInformation::GetDepends() +std::vector<std::string> const& cmComputeLinkInformation::GetDepends() const { return this->Depends; } std::vector<std::string> const& cmComputeLinkInformation::GetFrameworkPaths() + const { return this->FrameworkPaths; } const std::set<const cmGeneratorTarget*>& -cmComputeLinkInformation::GetSharedLibrariesLinked() +cmComputeLinkInformation::GetSharedLibrariesLinked() const { return this->SharedLibrariesLinked; } @@ -611,6 +611,9 @@ void cmComputeLinkInformation::AddItem(std::string const& item, if (!libName.empty()) { this->AddItem(libName, nullptr); } + } else if (tgt->GetType() == cmStateEnums::OBJECT_LIBRARY) { + // Ignore object library! + // Its object-files should already have been extracted for linking. } else { // Decide whether to use an import library. bool implib = @@ -1023,7 +1026,7 @@ void cmComputeLinkInformation::AddFullItem(std::string const& item) (generator.find("Visual Studio") != std::string::npos || generator.find("Xcode") != std::string::npos)) { std::string file = cmSystemTools::GetFilenameName(item); - if (!this->ExtractAnyLibraryName.find(file.c_str())) { + if (!this->ExtractAnyLibraryName.find(file)) { this->HandleBadFullItem(item, file); return; } @@ -1230,7 +1233,7 @@ void cmComputeLinkInformation::AddUserItem(std::string const& item, void cmComputeLinkInformation::AddFrameworkItem(std::string const& item) { // Try to separate the framework name and path. - if (!this->SplitFramework.find(item.c_str())) { + if (!this->SplitFramework.find(item)) { std::ostringstream e; e << "Could not parse framework path \"" << item << "\" " << "linked by target " << this->Target->GetName() << "."; @@ -1569,7 +1572,7 @@ void cmComputeLinkInformation::LoadImplicitLinkInfo() } std::vector<std::string> const& -cmComputeLinkInformation::GetRuntimeSearchPath() +cmComputeLinkInformation::GetRuntimeSearchPath() const { return this->OrderRuntimeSearchPath->GetOrderedDirectories(); } @@ -1635,7 +1638,7 @@ void cmComputeLinkInformation::AddLibraryRuntimeInfo( if (!is_shared_library) { // On some platforms (AIX) a shared library may look static. if (this->ArchivesMayBeShared) { - if (this->ExtractStaticLibraryName.find(file.c_str())) { + if (this->ExtractStaticLibraryName.find(file)) { // This is the name of a shared library or archive. is_shared_library = true; } @@ -1680,7 +1683,7 @@ static void cmCLI_ExpandListUnique(const char* str, } void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, - bool for_install) + bool for_install) const { // Select whether to generate runtime search directories. bool outputRuntime = @@ -1794,7 +1797,7 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, cmCLI_ExpandListUnique(this->RuntimeAlways.c_str(), runtimeDirs, emitted); } -std::string cmComputeLinkInformation::GetRPathString(bool for_install) +std::string cmComputeLinkInformation::GetRPathString(bool for_install) const { // Get the directories to use. std::vector<std::string> runtimeDirs; @@ -1822,7 +1825,7 @@ std::string cmComputeLinkInformation::GetRPathString(bool for_install) return rpath; } -std::string cmComputeLinkInformation::GetChrpathString() +std::string cmComputeLinkInformation::GetChrpathString() const { if (!this->RuntimeUseChrpath) { return ""; diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h index f8c6214..65c12da 100644 --- a/Source/cmComputeLinkInformation.h +++ b/Source/cmComputeLinkInformation.h @@ -48,21 +48,21 @@ public: cmGeneratorTarget const* Target; }; typedef std::vector<Item> ItemVector; - ItemVector const& GetItems(); - std::vector<std::string> const& GetDirectories(); - std::vector<std::string> const& GetDepends(); - std::vector<std::string> const& GetFrameworkPaths(); + ItemVector const& GetItems() const; + std::vector<std::string> const& GetDirectories() const; + std::vector<std::string> const& GetDepends() const; + std::vector<std::string> const& GetFrameworkPaths() const; std::string GetLinkLanguage() const { return this->LinkLanguage; } - std::vector<std::string> const& GetRuntimeSearchPath(); + std::vector<std::string> const& GetRuntimeSearchPath() const; std::string const& GetRuntimeFlag() const { return this->RuntimeFlag; } std::string const& GetRuntimeSep() const { return this->RuntimeSep; } - void GetRPath(std::vector<std::string>& runtimeDirs, bool for_install); - std::string GetRPathString(bool for_install); - std::string GetChrpathString(); - std::set<cmGeneratorTarget const*> const& GetSharedLibrariesLinked(); + void GetRPath(std::vector<std::string>& runtimeDirs, bool for_install) const; + std::string GetRPathString(bool for_install) const; + std::string GetChrpathString() const; + std::set<cmGeneratorTarget const*> const& GetSharedLibrariesLinked() const; std::string const& GetRPathLinkFlag() const { return this->RPathLinkFlag; } - std::string GetRPathLinkString(); + std::string GetRPathLinkString() const; std::string GetConfig() const { return this->Config; } private: @@ -78,13 +78,13 @@ private: std::set<cmGeneratorTarget const*> SharedLibrariesLinked; // Context information. - cmGeneratorTarget const* Target; - cmMakefile* Makefile; - cmGlobalGenerator* GlobalGenerator; - cmake* CMakeInstance; + cmGeneratorTarget const* const Target; + cmMakefile* const Makefile; + cmGlobalGenerator* const GlobalGenerator; + cmake* const CMakeInstance; // Configuration information. - std::string Config; + std::string const Config; std::string LinkLanguage; // Modes for dealing with dependent shared libraries. diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx index 18767a3..efdd3a5 100644 --- a/Source/cmComputeTargetDepends.cxx +++ b/Source/cmComputeTargetDepends.cxx @@ -211,11 +211,11 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index) if (depender->GetType() != cmStateEnums::EXECUTABLE && depender->GetType() != cmStateEnums::STATIC_LIBRARY && depender->GetType() != cmStateEnums::SHARED_LIBRARY && - depender->GetType() != cmStateEnums::MODULE_LIBRARY) { + depender->GetType() != cmStateEnums::MODULE_LIBRARY && + depender->GetType() != cmStateEnums::OBJECT_LIBRARY) { this->GlobalGenerator->GetCMakeInstance()->IssueMessage( cmake::FATAL_ERROR, - "Only executables and non-OBJECT libraries may " - "reference target objects.", + "Only executables and libraries may reference target objects.", depender->GetBacktrace()); return; } diff --git a/Source/cmDepends.cxx b/Source/cmDepends.cxx index cdab671..4716e14 100644 --- a/Source/cmDepends.cxx +++ b/Source/cmDepends.cxx @@ -7,7 +7,6 @@ #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmSystemTools.h" -#include "cmWorkingDirectory.h" #include "cmsys/FStream.hxx" #include <sstream> @@ -15,8 +14,7 @@ #include <utility> cmDepends::cmDepends(cmLocalGenerator* lg, const char* targetDir) - : CompileDirectory() - , LocalGenerator(lg) + : LocalGenerator(lg) , Verbose(false) , FileComparison(nullptr) , TargetDirectory(targetDir) @@ -73,9 +71,6 @@ bool cmDepends::Finalize(std::ostream& /*unused*/, std::ostream& /*unused*/) bool cmDepends::Check(const char* makeFile, const char* internalFile, std::map<std::string, DependencyVector>& validDeps) { - // Dependency checks must be done in proper working directory. - cmWorkingDirectory workdir(this->CompileDirectory); - // Check whether dependencies must be regenerated. bool okay = true; cmsys::ifstream fin(internalFile); diff --git a/Source/cmDepends.h b/Source/cmDepends.h index a4fee3c..4b9e05a 100644 --- a/Source/cmDepends.h +++ b/Source/cmDepends.h @@ -31,9 +31,6 @@ public: path from the build directory to the target file. */ cmDepends(cmLocalGenerator* lg = nullptr, const char* targetDir = ""); - /** at what level will the compile be done from */ - void SetCompileDirectory(const char* dir) { this->CompileDirectory = dir; } - /** Set the local generator for the directory in which we are scanning dependencies. This is not a full local generator; it has been setup to do relative path conversions for the current @@ -95,9 +92,6 @@ protected: virtual bool Finalize(std::ostream& makeDepends, std::ostream& internalDepends); - // The directory in which the build rule for the target file is executed. - std::string CompileDirectory; - // The local generator. cmLocalGenerator* LocalGenerator; diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx index 62bc8d9..34c0e94 100644 --- a/Source/cmDependsC.cxx +++ b/Source/cmDependsC.cxx @@ -96,9 +96,16 @@ bool cmDependsC::WriteDependencies(const std::set<std::string>& sources, std::set<std::string> dependencies; bool haveDeps = false; + std::string binDir = this->LocalGenerator->GetBinaryDirectory(); + + // Compute a path to the object file to write to the internal depend file. + // Any existing content of the internal depend file has already been + // loaded in ValidDeps with this path as a key. + std::string obj_i = this->LocalGenerator->ConvertToRelativePath(binDir, obj); + if (this->ValidDeps != nullptr) { std::map<std::string, DependencyVector>::const_iterator tmpIt = - this->ValidDeps->find(obj); + this->ValidDeps->find(obj_i); if (tmpIt != this->ValidDeps->end()) { dependencies.insert(tmpIt->second.begin(), tmpIt->second.end()); haveDeps = true; @@ -222,8 +229,6 @@ bool cmDependsC::WriteDependencies(const std::set<std::string>& sources, // written by the original local generator for this directory // convert the dependencies to paths relative to the home output // 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); internalDepends << obj_i << std::endl; diff --git a/Source/cmExportBuildAndroidMKGenerator.cxx b/Source/cmExportBuildAndroidMKGenerator.cxx index 817b5d9..0ceac85 100644 --- a/Source/cmExportBuildAndroidMKGenerator.cxx +++ b/Source/cmExportBuildAndroidMKGenerator.cxx @@ -41,7 +41,8 @@ void cmExportBuildAndroidMKGenerator::GenerateExpectedTargetsCode( } void cmExportBuildAndroidMKGenerator::GenerateImportTargetCode( - std::ostream& os, const cmGeneratorTarget* target) + std::ostream& os, cmGeneratorTarget const* target, + cmStateEnums::TargetType /*targetType*/) { std::string targetName = this->Namespace; targetName += target->GetExportName(); diff --git a/Source/cmExportBuildAndroidMKGenerator.h b/Source/cmExportBuildAndroidMKGenerator.h index c80839b..a9b6107 100644 --- a/Source/cmExportBuildAndroidMKGenerator.h +++ b/Source/cmExportBuildAndroidMKGenerator.h @@ -11,6 +11,7 @@ #include "cmExportBuildFileGenerator.h" #include "cmExportFileGenerator.h" +#include "cmStateTypes.h" class cmGeneratorTarget; @@ -47,8 +48,9 @@ protected: void GenerateImportHeaderCode(std::ostream& os, const std::string& config = "") override; void GenerateImportFooterCode(std::ostream& os) override; - void GenerateImportTargetCode(std::ostream& os, - const cmGeneratorTarget* target) override; + void GenerateImportTargetCode( + std::ostream& os, cmGeneratorTarget const* target, + cmStateEnums::TargetType /*targetType*/) override; void GenerateExpectedTargetsCode( std::ostream& os, const std::string& expectedTargets) override; void GenerateImportPropertyCode( diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index f7aa6e8..bbbc998 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -59,7 +59,7 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) this->LG->GetMakefile()->GetBacktrace()); return false; } - if (te->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (this->GetExportTargetType(te) == cmStateEnums::INTERFACE_LIBRARY) { this->GenerateRequiredCMakeVersion(os, "3.0.0"); } } @@ -71,7 +71,7 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) // Create all the imported targets. for (cmGeneratorTarget* gte : this->Exports) { - this->GenerateImportTargetCode(os, gte); + this->GenerateImportTargetCode(os, gte, this->GetExportTargetType(gte)); gte->Target->AppendBuildInterfaceIncludes(); @@ -97,6 +97,15 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) properties, missingTargets); this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gte, properties); + + std::string errorMessage; + if (!this->PopulateExportProperties(gte, properties, errorMessage)) { + this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage( + cmake::FATAL_ERROR, errorMessage, + this->LG->GetMakefile()->GetBacktrace()); + return false; + } + const bool newCMP0022Behavior = gte->GetPolicyStatusCMP0022() != cmPolicies::WARN && gte->GetPolicyStatusCMP0022() != cmPolicies::OLD; @@ -128,12 +137,13 @@ void cmExportBuildFileGenerator::GenerateImportTargetsConfig( // Collect import properties for this target. ImportPropertyMap properties; - if (target->GetType() != cmStateEnums::INTERFACE_LIBRARY) { + if (this->GetExportTargetType(target) != cmStateEnums::INTERFACE_LIBRARY) { this->SetImportLocationProperty(config, suffix, target, properties); } if (!properties.empty()) { // Get the rest of the target details. - if (target->GetType() != cmStateEnums::INTERFACE_LIBRARY) { + if (this->GetExportTargetType(target) != + cmStateEnums::INTERFACE_LIBRARY) { this->SetImportDetailProperties(config, suffix, target, properties, missingTargets); this->SetImportLinkInterface(config, suffix, @@ -153,6 +163,21 @@ void cmExportBuildFileGenerator::GenerateImportTargetsConfig( } } +cmStateEnums::TargetType cmExportBuildFileGenerator::GetExportTargetType( + cmGeneratorTarget const* target) const +{ + cmStateEnums::TargetType targetType = target->GetType(); + // An object library exports as an interface library if we cannot + // tell clients where to find the objects. This is sufficient + // to support transitive usage requirements on other targets that + // use the object library. + if (targetType == cmStateEnums::OBJECT_LIBRARY && + !this->LG->GetGlobalGenerator()->HasKnownObjectFileLocation(nullptr)) { + targetType = cmStateEnums::INTERFACE_LIBRARY; + } + return targetType; +} + void cmExportBuildFileGenerator::SetExportSet(cmExportSet* exportSet) { this->ExportSet = exportSet; diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h index 6457a77..ada2709 100644 --- a/Source/cmExportBuildFileGenerator.h +++ b/Source/cmExportBuildFileGenerator.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include "cmExportFileGenerator.h" +#include "cmStateTypes.h" #include <iosfwd> #include <string> @@ -53,6 +54,8 @@ protected: void GenerateImportTargetsConfig( std::ostream& os, const std::string& config, std::string const& suffix, std::vector<std::string>& missingTargets) override; + cmStateEnums::TargetType GetExportTargetType( + cmGeneratorTarget const* target) const; void HandleMissingTarget(std::string& link_libs, std::vector<std::string>& missingTargets, cmGeneratorTarget* depender, diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx index c8a727d..655ebe8 100644 --- a/Source/cmExportCommand.cxx +++ b/Source/cmExportCommand.cxx @@ -146,17 +146,6 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args, } if (cmTarget* target = gg->FindTarget(currentTarget)) { - if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) { - std::string reason; - if (!this->Makefile->GetGlobalGenerator() - ->HasKnownObjectFileLocation(&reason)) { - std::ostringstream e; - e << "given OBJECT library \"" << currentTarget - << "\" which may not be exported" << reason << "."; - this->SetError(e.str()); - return false; - } - } if (target->GetType() == cmStateEnums::UTILITY) { this->SetError("given custom target \"" + currentTarget + "\" which may not be exported."); diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 434abdc..2dcbfa0 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -11,6 +11,8 @@ #include "cmMakefile.h" #include "cmOutputConverter.h" #include "cmPolicies.h" +#include "cmProperty.h" +#include "cmPropertyMap.h" #include "cmStateTypes.h" #include "cmSystemTools.h" #include "cmTarget.h" @@ -901,8 +903,10 @@ void cmExportFileGenerator::GenerateExpectedTargetsCode( "\n\n"; /* clang-format on */ } + void cmExportFileGenerator::GenerateImportTargetCode( - std::ostream& os, const cmGeneratorTarget* target) + std::ostream& os, cmGeneratorTarget const* target, + cmStateEnums::TargetType targetType) { // Construct the imported target name. std::string targetName = this->Namespace; @@ -911,7 +915,7 @@ void cmExportFileGenerator::GenerateImportTargetCode( // Create the imported target. os << "# Create imported target " << targetName << "\n"; - switch (target->GetType()) { + switch (targetType) { case cmStateEnums::EXECUTABLE: os << "add_executable(" << targetName << " IMPORTED)\n"; break; @@ -1095,3 +1099,41 @@ void cmExportFileGenerator::GenerateImportedFileChecksCode( os << ")\n\n"; } + +bool cmExportFileGenerator::PopulateExportProperties( + cmGeneratorTarget* gte, ImportPropertyMap& properties, + std::string& errorMessage) +{ + auto& targetProperties = gte->Target->GetProperties(); + const auto& exportProperties = targetProperties.find("EXPORT_PROPERTIES"); + if (exportProperties != targetProperties.end()) { + std::vector<std::string> propsToExport; + cmSystemTools::ExpandListArgument(exportProperties->second.GetValue(), + propsToExport); + for (auto& prop : propsToExport) { + /* Black list reserved properties */ + if (cmSystemTools::StringStartsWith(prop, "IMPORTED_") || + cmSystemTools::StringStartsWith(prop, "INTERFACE_")) { + std::ostringstream e; + e << "Target \"" << gte->Target->GetName() << "\" contains property \"" + << prop << "\" in EXPORT_PROPERTIES but IMPORTED_* and INTERFACE_* " + << "properties are reserved."; + errorMessage = e.str(); + return false; + } + auto propertyValue = targetProperties.GetPropertyValue(prop); + std::string evaluatedValue = cmGeneratorExpression::Preprocess( + propertyValue, cmGeneratorExpression::StripAllGeneratorExpressions); + if (evaluatedValue != propertyValue) { + std::ostringstream e; + e << "Target \"" << gte->Target->GetName() << "\" contains property \"" + << prop << "\" in EXPORT_PROPERTIES but this property contains a " + << "generator expression. This is not allowed."; + errorMessage = e.str(); + return false; + } + properties[prop] = propertyValue; + } + } + return true; +} diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index 985c8f6..954e6c5 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include "cmGeneratorExpression.h" +#include "cmStateTypes.h" #include "cmVersion.h" #include "cmVersionConfig.h" @@ -76,7 +77,8 @@ protected: virtual void GenerateImportFooterCode(std::ostream& os); void GenerateImportVersionCode(std::ostream& os); virtual void GenerateImportTargetCode(std::ostream& os, - cmGeneratorTarget const* target); + cmGeneratorTarget const* target, + cmStateEnums::TargetType targetType); virtual void GenerateImportPropertyCode(std::ostream& os, const std::string& config, cmGeneratorTarget const* target, @@ -166,6 +168,10 @@ protected: virtual void GenerateRequiredCMakeVersion(std::ostream& os, const char* versionString); + bool PopulateExportProperties(cmGeneratorTarget* gte, + ImportPropertyMap& properties, + std::string& errorMessage); + // The namespace in which the exports are placed in the generated file. std::string Namespace; diff --git a/Source/cmExportInstallAndroidMKGenerator.cxx b/Source/cmExportInstallAndroidMKGenerator.cxx index fe565e6..9bc8089 100644 --- a/Source/cmExportInstallAndroidMKGenerator.cxx +++ b/Source/cmExportInstallAndroidMKGenerator.cxx @@ -55,7 +55,8 @@ void cmExportInstallAndroidMKGenerator::GenerateImportFooterCode(std::ostream&) } void cmExportInstallAndroidMKGenerator::GenerateImportTargetCode( - std::ostream& os, const cmGeneratorTarget* target) + std::ostream& os, cmGeneratorTarget const* target, + cmStateEnums::TargetType /*targetType*/) { std::string targetName = this->Namespace; targetName += target->GetExportName(); diff --git a/Source/cmExportInstallAndroidMKGenerator.h b/Source/cmExportInstallAndroidMKGenerator.h index 91554ee..8883ffa 100644 --- a/Source/cmExportInstallAndroidMKGenerator.h +++ b/Source/cmExportInstallAndroidMKGenerator.h @@ -12,6 +12,7 @@ #include "cmExportFileGenerator.h" #include "cmExportInstallFileGenerator.h" +#include "cmStateTypes.h" class cmGeneratorTarget; class cmInstallExportGenerator; @@ -41,8 +42,9 @@ protected: void GenerateImportHeaderCode(std::ostream& os, const std::string& config = "") override; void GenerateImportFooterCode(std::ostream& os) override; - void GenerateImportTargetCode(std::ostream& os, - const cmGeneratorTarget* target) override; + void GenerateImportTargetCode( + std::ostream& os, cmGeneratorTarget const* target, + cmStateEnums::TargetType /*targetType*/) override; void GenerateExpectedTargetsCode( std::ostream& os, const std::string& expectedTargets) override; void GenerateImportPropertyCode( diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index 954b561..63d04a6 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -75,11 +75,12 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) // Create all the imported targets. for (cmTargetExport* te : allTargets) { cmGeneratorTarget* gt = te->Target; + cmStateEnums::TargetType targetType = this->GetExportTargetType(te); requiresConfigFiles = - requiresConfigFiles || gt->GetType() != cmStateEnums::INTERFACE_LIBRARY; + requiresConfigFiles || targetType != cmStateEnums::INTERFACE_LIBRARY; - this->GenerateImportTargetCode(os, gt); + this->GenerateImportTargetCode(os, gt, targetType); ImportPropertyMap properties; @@ -103,6 +104,12 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) cmGeneratorExpression::InstallInterface, properties, missingTargets); + std::string errorMessage; + if (!this->PopulateExportProperties(gt, properties, errorMessage)) { + cmSystemTools::Error(errorMessage.c_str()); + return false; + } + const bool newCMP0022Behavior = gt->GetPolicyStatusCMP0022() != cmPolicies::WARN && gt->GetPolicyStatusCMP0022() != cmPolicies::OLD; @@ -114,7 +121,7 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) require2_8_12 = true; } } - if (gt->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (targetType == cmStateEnums::INTERFACE_LIBRARY) { require3_0_0 = true; } if (gt->GetProperty("INTERFACE_SOURCES")) { @@ -308,7 +315,7 @@ void cmExportInstallFileGenerator::GenerateImportTargetsConfig( // Add each target in the set to the export. for (cmTargetExport* te : *this->IEGen->GetExportSet()->GetTargetExports()) { // Collect import properties for this target. - if (te->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (this->GetExportTargetType(te) == cmStateEnums::INTERFACE_LIBRARY) { continue; } @@ -426,6 +433,19 @@ void cmExportInstallFileGenerator::SetImportLocationProperty( } } +cmStateEnums::TargetType cmExportInstallFileGenerator::GetExportTargetType( + cmTargetExport const* targetExport) const +{ + cmStateEnums::TargetType targetType = targetExport->Target->GetType(); + // An OBJECT library installed with no OBJECTS DESTINATION + // is transformed to an INTERFACE library. + if (targetType == cmStateEnums::OBJECT_LIBRARY && + targetExport->ObjectsGenerator == nullptr) { + targetType = cmStateEnums::INTERFACE_LIBRARY; + } + return targetType; +} + void cmExportInstallFileGenerator::HandleMissingTarget( std::string& link_libs, std::vector<std::string>& missingTargets, cmGeneratorTarget* depender, cmGeneratorTarget* dependee) diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h index cda8433..ea607fb 100644 --- a/Source/cmExportInstallFileGenerator.h +++ b/Source/cmExportInstallFileGenerator.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include "cmExportFileGenerator.h" +#include "cmStateTypes.h" #include <iosfwd> #include <map> @@ -17,6 +18,7 @@ class cmGeneratorTarget; class cmGlobalGenerator; class cmInstallExportGenerator; class cmInstallTargetGenerator; +class cmTargetExport; /** \class cmExportInstallFileGenerator * \brief Generate a file exporting targets from an install tree. @@ -57,6 +59,8 @@ protected: void GenerateImportTargetsConfig( std::ostream& os, const std::string& config, std::string const& suffix, std::vector<std::string>& missingTargets) override; + cmStateEnums::TargetType GetExportTargetType( + cmTargetExport const* targetExport) const; void HandleMissingTarget(std::string& link_libs, std::vector<std::string>& missingTargets, cmGeneratorTarget* depender, diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx index ae8cd37..87648cb 100644 --- a/Source/cmExportTryCompileFileGenerator.cxx +++ b/Source/cmExportTryCompileFileGenerator.cxx @@ -33,7 +33,7 @@ bool cmExportTryCompileFileGenerator::GenerateMainFile(std::ostream& os) this->Exports.pop_back(); if (emitted.insert(te).second) { emittedDeps.insert(te); - this->GenerateImportTargetCode(os, te); + this->GenerateImportTargetCode(os, te, te->GetType()); ImportPropertyMap properties; diff --git a/Source/cmExtraCodeLiteGenerator.cxx b/Source/cmExtraCodeLiteGenerator.cxx index 4dbaa3f..c7c780c 100644 --- a/Source/cmExtraCodeLiteGenerator.cxx +++ b/Source/cmExtraCodeLiteGenerator.cxx @@ -408,7 +408,6 @@ void cmExtraCodeLiteGenerator::CreateProjectSourceEntries( const std::string& projectPath, const cmMakefile* mf, const std::string& projectType, const std::string& targetName) { - cmXMLWriter& xml(*_xml); FindMatchingHeaderfiles(cFiles, otherFiles); // Create 2 virtual folders: src and include @@ -469,10 +468,14 @@ void cmExtraCodeLiteGenerator::CreateProjectSourceEntries( xml.EndElement(); // ResourceCompiler xml.StartElement("General"); - std::string outputPath = mf->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH"); + std::string outputPath = + mf->GetSafeDefinition("CMAKE_RUNTIME_OUTPUT_DIRECTORY"); + if (outputPath.empty()) { + outputPath = mf->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH"); + } std::string relapath; if (!outputPath.empty()) { - relapath = cmSystemTools::RelativePath(this->WorkspacePath, outputPath); + relapath = cmSystemTools::RelativePath(projectPath, outputPath); xml.Attribute("OutputFile", relapath + "/$(ProjectName)"); } else { xml.Attribute("OutputFile", "$(IntermediateDirectory)/$(ProjectName)"); @@ -635,7 +638,7 @@ std::string cmExtraCodeLiteGenerator::GetBuildCommand( if (generator == "NMake Makefiles" || generator == "Ninja") { ss << make; } else if (generator == "MinGW Makefiles" || generator == "Unix Makefiles") { - ss << make << " -j " << this->CpuCount; + ss << make << " -f$(ProjectPath)/Makefile -j " << this->CpuCount; } if (!targetName.empty()) { ss << " " << targetName; diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index d3dcc01..90b943b 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -160,6 +160,12 @@ bool cmFileCommand::InitialPass(std::vector<std::string> const& args, if (subCommand == "TO_NATIVE_PATH") { return this->HandleCMakePathCommand(args, true); } + if (subCommand == "TOUCH") { + return this->HandleTouchCommand(args, true); + } + if (subCommand == "TOUCH_NOCREATE") { + return this->HandleTouchCommand(args, false); + } if (subCommand == "TIMESTAMP") { return this->HandleTimestampCommand(args); } @@ -751,9 +757,9 @@ bool cmFileCommand::HandleGlobCommand(std::vector<std::string> const& args, } } - std::string output; - bool first = true; - for (; i != args.end(); ++i) { + std::vector<std::string> files; + bool warnFollowedSymlinks = false; + while (i != args.end()) { if (*i == "LIST_DIRECTORIES") { ++i; if (i != args.end()) { @@ -771,103 +777,105 @@ bool cmFileCommand::HandleGlobCommand(std::vector<std::string> const& args, this->SetError("LIST_DIRECTORIES missing bool value."); return false; } - continue; - } - - if (recurse && (*i == "FOLLOW_SYMLINKS")) { + ++i; + if (i == args.end()) { + this->SetError("GLOB requires a glob expression after the bool."); + return false; + } + } else if (*i == "FOLLOW_SYMLINKS") { + if (!recurse) { + this->SetError("FOLLOW_SYMLINKS is not a valid parameter for GLOB."); + return false; + } explicitFollowSymlinks = true; g.RecurseThroughSymlinksOn(); ++i; if (i == args.end()) { this->SetError( - "GLOB_RECURSE requires a glob expression after FOLLOW_SYMLINKS"); + "GLOB_RECURSE requires a glob expression after FOLLOW_SYMLINKS."); return false; } - } - - if (*i == "RELATIVE") { + } else if (*i == "RELATIVE") { ++i; // skip RELATIVE if (i == args.end()) { - this->SetError("GLOB requires a directory after the RELATIVE tag"); + this->SetError("GLOB requires a directory after the RELATIVE tag."); return false; } g.SetRelative(i->c_str()); ++i; if (i == args.end()) { - this->SetError("GLOB requires a glob expression after the directory"); + this->SetError("GLOB requires a glob expression after the directory."); return false; } - } - - cmsys::Glob::GlobMessages globMessages; - if (!cmsys::SystemTools::FileIsFullPath(*i)) { - std::string expr = this->Makefile->GetCurrentSourceDirectory(); - // Handle script mode - if (!expr.empty()) { - expr += "/" + *i; - g.FindFiles(expr, &globMessages); - } else { - g.FindFiles(*i, &globMessages); - } } else { - g.FindFiles(*i, &globMessages); - } - - if (!globMessages.empty()) { - bool shouldExit = false; - for (cmsys::Glob::Message const& globMessage : globMessages) { - if (globMessage.type == cmsys::Glob::cyclicRecursion) { - this->Makefile->IssueMessage( - cmake::AUTHOR_WARNING, - "Cyclic recursion detected while globbing for '" + *i + "':\n" + - globMessage.content); + std::string expr = *i; + if (!cmsys::SystemTools::FileIsFullPath(*i)) { + expr = this->Makefile->GetCurrentSourceDirectory(); + // Handle script mode + if (!expr.empty()) { + expr += "/" + *i; } else { - this->Makefile->IssueMessage( - cmake::FATAL_ERROR, "Error has occurred while globbing for '" + - *i + "' - " + globMessage.content); - shouldExit = true; + expr = *i; } } - if (shouldExit) { - return false; + + cmsys::Glob::GlobMessages globMessages; + g.FindFiles(expr, &globMessages); + + if (!globMessages.empty()) { + bool shouldExit = false; + for (cmsys::Glob::Message const& globMessage : globMessages) { + if (globMessage.type == cmsys::Glob::cyclicRecursion) { + this->Makefile->IssueMessage( + cmake::AUTHOR_WARNING, + "Cyclic recursion detected while globbing for '" + *i + "':\n" + + globMessage.content); + } else { + this->Makefile->IssueMessage( + cmake::FATAL_ERROR, "Error has occurred while globbing for '" + + *i + "' - " + globMessage.content); + shouldExit = true; + } + } + if (shouldExit) { + return false; + } } - } - std::vector<std::string>::size_type cc; - std::vector<std::string>& files = g.GetFiles(); - std::sort(files.begin(), files.end()); - for (cc = 0; cc < files.size(); cc++) { - if (!first) { - output += ";"; + if (recurse && !explicitFollowSymlinks && + g.GetFollowedSymlinkCount() != 0) { + warnFollowedSymlinks = true; } - output += files[cc]; - first = false; + + std::vector<std::string>& foundFiles = g.GetFiles(); + files.insert(files.end(), foundFiles.begin(), foundFiles.end()); + ++i; } } - if (recurse && !explicitFollowSymlinks) { - switch (status) { - case cmPolicies::REQUIRED_IF_USED: - case cmPolicies::REQUIRED_ALWAYS: - case cmPolicies::NEW: - // Correct behavior, yay! - break; - case cmPolicies::OLD: - // Probably not really the expected behavior, but the author explicitly - // asked for the old behavior... no warning. - case cmPolicies::WARN: - // Possibly unexpected old behavior *and* we actually traversed - // symlinks without being explicitly asked to: warn the author. - if (g.GetFollowedSymlinkCount() != 0) { - this->Makefile->IssueMessage( - cmake::AUTHOR_WARNING, - cmPolicies::GetPolicyWarning(cmPolicies::CMP0009)); - } - break; - } + switch (status) { + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + // Correct behavior, yay! + break; + case cmPolicies::OLD: + // Probably not really the expected behavior, but the author explicitly + // asked for the old behavior... no warning. + case cmPolicies::WARN: + // Possibly unexpected old behavior *and* we actually traversed + // symlinks without being explicitly asked to: warn the author. + if (warnFollowedSymlinks) { + this->Makefile->IssueMessage( + cmake::AUTHOR_WARNING, + cmPolicies::GetPolicyWarning(cmPolicies::CMP0009)); + } + break; } - this->Makefile->AddDefinition(variable, output.c_str()); + std::sort(files.begin(), files.end()); + files.erase(std::unique(files.begin(), files.end()), files.end()); + this->Makefile->AddDefinition(variable, cmJoin(files, ";").c_str()); return true; } @@ -905,6 +913,38 @@ bool cmFileCommand::HandleMakeDirectoryCommand( return true; } +bool cmFileCommand::HandleTouchCommand(std::vector<std::string> const& args, + bool create) +{ + // File command has at least one argument + assert(args.size() > 1); + + std::vector<std::string>::const_iterator i = args.begin(); + + i++; // Get rid of subcommand + + for (; i != args.end(); ++i) { + std::string tfile = *i; + if (!cmsys::SystemTools::FileIsFullPath(tfile)) { + tfile = this->Makefile->GetCurrentSourceDirectory(); + tfile += "/" + *i; + } + if (!this->Makefile->CanIWriteThisFile(tfile)) { + std::string e = + "attempted to touch a file: " + tfile + " in a source directory."; + this->SetError(e); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + if (!cmSystemTools::Touch(tfile, create)) { + std::string error = "problem touching file: " + tfile; + this->SetError(error); + return false; + } + } + return true; +} + bool cmFileCommand::HandleDifferentCommand( std::vector<std::string> const& args) { diff --git a/Source/cmFileCommand.h b/Source/cmFileCommand.h index 17269f3..719dca2 100644 --- a/Source/cmFileCommand.h +++ b/Source/cmFileCommand.h @@ -39,6 +39,7 @@ protected: bool HandleHashCommand(std::vector<std::string> const& args); bool HandleStringsCommand(std::vector<std::string> const& args); bool HandleGlobCommand(std::vector<std::string> const& args, bool recurse); + bool HandleTouchCommand(std::vector<std::string> const& args, bool create); bool HandleMakeDirectoryCommand(std::vector<std::string> const& args); bool HandleRelativePathCommand(std::vector<std::string> const& args); diff --git a/Source/cmFileTimeComparison.h b/Source/cmFileTimeComparison.h index b1f8ed6..114989b 100644 --- a/Source/cmFileTimeComparison.h +++ b/Source/cmFileTimeComparison.h @@ -8,9 +8,9 @@ class cmFileTimeComparisonInternal; /** \class cmFileTimeComparison - * \brief Helper class for performing globbing searches. + * \brief Helper class for comparing file modification times. * - * Finds all files that match a given globbing expression. + * Compare file modification times or test if file modification times differ. */ class cmFileTimeComparison { diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx index 417cdd2..865595b 100644 --- a/Source/cmFindBase.cxx +++ b/Source/cmFindBase.cxx @@ -67,8 +67,6 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn) } this->AlreadyInCache = false; - this->SelectDefaultNoPackageRootPath(); - // Find the current root path mode. this->SelectDefaultRootPathMode(); @@ -206,16 +204,12 @@ void cmFindBase::FillPackageRootPath() { cmSearchPath& paths = this->LabeledPaths[PathLabel::PackageRoot]; - // Add package specific search prefixes - // NOTE: This should be using const_reverse_iterator but HP aCC and - // Oracle sunCC both currently have standard library issues - // with the reverse iterator APIs. - for (std::deque<std::string>::reverse_iterator pkg = - this->Makefile->FindPackageModuleStack.rbegin(); - pkg != this->Makefile->FindPackageModuleStack.rend(); ++pkg) { - std::string varName = *pkg + "_ROOT"; - paths.AddCMakePrefixPath(varName); - paths.AddEnvPrefixPath(varName); + // Add the PACKAGE_ROOT_PATH from each enclosing find_package call. + for (std::deque<std::vector<std::string>>::const_reverse_iterator pkgPaths = + this->Makefile->FindPackageRootPathStack.rbegin(); + pkgPaths != this->Makefile->FindPackageRootPathStack.rend(); + ++pkgPaths) { + paths.AddPrefixPaths(*pkgPaths); } paths.AddSuffixes(this->SearchPathSuffixes); @@ -225,8 +219,8 @@ void cmFindBase::FillCMakeVariablePath() { cmSearchPath& paths = this->LabeledPaths[PathLabel::CMake]; - // Add CMake varibles of the same name as the previous environment - // varibles CMAKE_*_PATH to be used most of the time with -D + // Add CMake variables of the same name as the previous environment + // variables CMAKE_*_PATH to be used most of the time with -D // command line options std::string var = "CMAKE_"; var += this->CMakePathName; diff --git a/Source/cmFindCommon.cxx b/Source/cmFindCommon.cxx index 4a467f3..64108d7 100644 --- a/Source/cmFindCommon.cxx +++ b/Source/cmFindCommon.cxx @@ -88,13 +88,6 @@ void cmFindCommon::InitializeSearchPathGroups() std::make_pair(PathLabel::Guess, cmSearchPath(this))); } -void cmFindCommon::SelectDefaultNoPackageRootPath() -{ - if (!this->Makefile->IsOn("__UNDOCUMENTED_CMAKE_FIND_PACKAGE_ROOT")) { - this->NoPackageRootPath = true; - } -} - void cmFindCommon::SelectDefaultRootPathMode() { // Check the policy variable for this find command type. diff --git a/Source/cmFindCommon.h b/Source/cmFindCommon.h index b237f1b..89ff174 100644 --- a/Source/cmFindCommon.h +++ b/Source/cmFindCommon.h @@ -84,9 +84,6 @@ protected: /** Compute final search path list (reroot + trailing slash). */ void ComputeFinalPaths(); - /** Decide whether to enable the PACKAGE_ROOT search entries. */ - void SelectDefaultNoPackageRootPath(); - /** Compute the current default root path mode. */ void SelectDefaultRootPathMode(); diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 2f3a85b..46854f7 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -21,6 +21,7 @@ #include "cmAlgorithms.h" #include "cmMakefile.h" +#include "cmPolicies.h" #include "cmSearchPath.h" #include "cmState.h" #include "cmStateTypes.h" @@ -209,8 +210,6 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args, this->SortDirection = strcmp(sd, "ASC") == 0 ? Asc : Dec; } - this->SelectDefaultNoPackageRootPath(); - // Find the current root path mode. this->SelectDefaultRootPathMode(); @@ -454,6 +453,38 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args, return true; } + { + // Allocate a PACKAGE_ROOT_PATH for the current find_package call. + this->Makefile->FindPackageRootPathStack.emplace_back(); + std::vector<std::string>& rootPaths = + *this->Makefile->FindPackageRootPathStack.rbegin(); + + // Add root paths from <PackageName>_ROOT CMake and environment variables, + // subject to CMP0074. + switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0074)) { + case cmPolicies::WARN: + this->Makefile->MaybeWarnCMP0074(this->Name); + CM_FALLTHROUGH; + case cmPolicies::OLD: + // OLD behavior is to ignore the <pkg>_ROOT variables. + break; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + this->Makefile->IssueMessage( + cmake::FATAL_ERROR, + cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0074)); + break; + case cmPolicies::NEW: { + // NEW behavior is to honor the <pkg>_ROOT variables. + std::string const rootVar = this->Name + "_ROOT"; + if (const char* pkgRoot = this->Makefile->GetDefinition(rootVar)) { + cmSystemTools::ExpandListArgument(pkgRoot, rootPaths, false); + } + cmSystemTools::GetPath(rootPaths, rootVar.c_str()); + } break; + } + } + this->SetModuleVariables(components); // See if there is a Find<package>.cmake module. @@ -589,9 +620,6 @@ void cmFindPackageCommand::SetModuleVariables(const std::string& components) exact += "_FIND_VERSION_EXACT"; this->AddFindDefinition(exact, this->VersionExact ? "1" : "0"); } - - // Push on to the package stack - this->Makefile->FindPackageModuleStack.push_back(this->Name); } void cmFindPackageCommand::AddFindDefinition(const std::string& var, @@ -1076,7 +1104,7 @@ void cmFindPackageCommand::AppendSuccessInformation() this->RestoreFindDefinitions(); // Pop the package stack - this->Makefile->FindPackageModuleStack.pop_back(); + this->Makefile->FindPackageRootPathStack.pop_back(); } void cmFindPackageCommand::ComputePrefixes() @@ -1116,16 +1144,14 @@ void cmFindPackageCommand::FillPrefixesPackageRoot() { cmSearchPath& paths = this->LabeledPaths[PathLabel::PackageRoot]; - // Add package specific search prefixes - // NOTE: This should be using const_reverse_iterator but HP aCC and - // Oracle sunCC both currently have standard library issues - // with the reverse iterator APIs. - for (std::deque<std::string>::reverse_iterator pkg = - this->Makefile->FindPackageModuleStack.rbegin(); - pkg != this->Makefile->FindPackageModuleStack.rend(); ++pkg) { - std::string varName = *pkg + "_ROOT"; - paths.AddCMakePath(varName); - paths.AddEnvPath(varName); + // Add the PACKAGE_ROOT_PATH from each enclosing find_package call. + for (std::deque<std::vector<std::string>>::const_reverse_iterator pkgPaths = + this->Makefile->FindPackageRootPathStack.rbegin(); + pkgPaths != this->Makefile->FindPackageRootPathStack.rend(); + ++pkgPaths) { + for (std::string const& path : *pkgPaths) { + paths.AddPath(path); + } } } @@ -2039,7 +2065,7 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in) common.push_back("lib"); common.push_back("share"); - // PREFIX/(lib/ARCH|lib|share)/cmake/(Foo|foo|FOO).*/ + // PREFIX/(lib/ARCH|lib*|share)/cmake/(Foo|foo|FOO).*/ { cmFindPackageFileList lister(this); lister / cmFileListGeneratorFixed(prefix) / @@ -2052,7 +2078,7 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in) } } - // PREFIX/(lib/ARCH|lib|share)/(Foo|foo|FOO).*/ + // PREFIX/(lib/ARCH|lib*|share)/(Foo|foo|FOO).*/ { cmFindPackageFileList lister(this); lister / cmFileListGeneratorFixed(prefix) / @@ -2064,7 +2090,7 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in) } } - // PREFIX/(lib/ARCH|lib|share)/(Foo|foo|FOO).*/(cmake|CMake)/ + // PREFIX/(lib/ARCH|lib*|share)/(Foo|foo|FOO).*/(cmake|CMake)/ { cmFindPackageFileList lister(this); lister / cmFileListGeneratorFixed(prefix) / @@ -2077,7 +2103,7 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in) } } - // PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib|share)/cmake/(Foo|foo|FOO).*/ + // PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib*|share)/cmake/(Foo|foo|FOO).*/ { cmFindPackageFileList lister(this); lister / cmFileListGeneratorFixed(prefix) / @@ -2092,7 +2118,7 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in) } } - // PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib|share)/(Foo|foo|FOO).*/ + // PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib*|share)/(Foo|foo|FOO).*/ { cmFindPackageFileList lister(this); lister / cmFileListGeneratorFixed(prefix) / @@ -2106,7 +2132,7 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in) } } - // PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib|share)/(Foo|foo|FOO).*/(cmake|CMake)/ + // PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib*|share)/(Foo|foo|FOO).*/(cmake|CMake)/ { cmFindPackageFileList lister(this); lister / cmFileListGeneratorFixed(prefix) / diff --git a/Source/cmGeneratorExpressionEvaluator.h b/Source/cmGeneratorExpressionEvaluator.h index 92dac79..0561799 100644 --- a/Source/cmGeneratorExpressionEvaluator.h +++ b/Source/cmGeneratorExpressionEvaluator.h @@ -7,6 +7,7 @@ #include <stddef.h> #include <string> +#include <utility> #include <vector> struct cmGeneratorExpressionContext; @@ -64,17 +65,16 @@ private: struct GeneratorExpressionContent : public cmGeneratorExpressionEvaluator { GeneratorExpressionContent(const char* startContent, size_t length); - void SetIdentifier( - std::vector<cmGeneratorExpressionEvaluator*> const& identifier) + + void SetIdentifier(std::vector<cmGeneratorExpressionEvaluator*> identifier) { - this->IdentifierChildren = identifier; + this->IdentifierChildren = std::move(identifier); } void SetParameters( - std::vector<std::vector<cmGeneratorExpressionEvaluator*>> const& - parameters) + std::vector<std::vector<cmGeneratorExpressionEvaluator*>> parameters) { - this->ParamChildren = parameters; + this->ParamChildren = std::move(parameters); } Type GetType() const override diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index c1f1ee4..09b7faf 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -275,6 +275,96 @@ static const struct EqualNode : public cmGeneratorExpressionNode } } equalNode; +static const struct InListNode : public cmGeneratorExpressionNode +{ + InListNode() {} + + int NumExpectedParameters() const override { return 2; } + + std::string Evaluate( + const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* /*context*/, + const GeneratorExpressionContent* /*content*/, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override + { + std::vector<std::string> values; + cmSystemTools::ExpandListArgument(parameters[1], values); + if (values.empty()) { + return "0"; + } + + return std::find(values.cbegin(), values.cend(), parameters.front()) == + values.cend() + ? "0" + : "1"; + } +} inListNode; + +static const struct TargetExistsNode : public cmGeneratorExpressionNode +{ + TargetExistsNode() {} + + int NumExpectedParameters() const override { return 1; } + + std::string Evaluate( + const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override + { + if (parameters.size() != 1) { + reportError(context, content->GetOriginalExpression(), + "$<TARGET_EXISTS:...> expression requires one parameter"); + return std::string(); + } + + std::string targetName = parameters.front(); + if (targetName.empty() || + !cmGeneratorExpression::IsValidTargetName(targetName)) { + reportError(context, content->GetOriginalExpression(), + "$<TARGET_EXISTS:tgt> expression requires a non-empty " + "valid target name."); + return std::string(); + } + + return context->LG->GetMakefile()->FindTargetToUse(targetName) ? "1" : "0"; + } +} targetExistsNode; + +static const struct TargetNameIfExistsNode : public cmGeneratorExpressionNode +{ + TargetNameIfExistsNode() {} + + int NumExpectedParameters() const override { return 1; } + + std::string Evaluate( + const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override + { + if (parameters.size() != 1) { + reportError(context, content->GetOriginalExpression(), + "$<TARGET_NAME_IF_EXISTS:...> expression requires one " + "parameter"); + return std::string(); + } + + std::string targetName = parameters.front(); + if (targetName.empty() || + !cmGeneratorExpression::IsValidTargetName(targetName)) { + reportError(context, content->GetOriginalExpression(), + "$<TARGET_NAME_IF_EXISTS:tgt> expression requires a " + "non-empty valid target name."); + return std::string(); + } + + return context->LG->GetMakefile()->FindTargetToUse(targetName) + ? targetName + : std::string(); + } +} targetNameIfExistsNode; + static const struct LowerCaseNode : public cmGeneratorExpressionNode { LowerCaseNode() {} @@ -1827,6 +1917,7 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( nodeMap["TARGET_BUNDLE_CONTENT_DIR"] = &targetBundleContentDirNode; nodeMap["STREQUAL"] = &strEqualNode; nodeMap["EQUAL"] = &equalNode; + nodeMap["IN_LIST"] = &inListNode; nodeMap["LOWER_CASE"] = &lowerCaseNode; nodeMap["UPPER_CASE"] = &upperCaseNode; nodeMap["MAKE_C_IDENTIFIER"] = &makeCIdentifierNode; @@ -1839,6 +1930,8 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( nodeMap["TARGET_NAME"] = &targetNameNode; nodeMap["TARGET_OBJECTS"] = &targetObjectsNode; nodeMap["TARGET_POLICY"] = &targetPolicyNode; + nodeMap["TARGET_EXISTS"] = &targetExistsNode; + nodeMap["TARGET_NAME_IF_EXISTS"] = &targetNameIfExistsNode; nodeMap["BUILD_INTERFACE"] = &buildInterfaceNode; nodeMap["INSTALL_INTERFACE"] = &installInterfaceNode; nodeMap["INSTALL_PREFIX"] = &installPrefixNode; diff --git a/Source/cmGeneratorExpressionParser.cxx b/Source/cmGeneratorExpressionParser.cxx index 278de04..7b4dc7b 100644 --- a/Source/cmGeneratorExpressionParser.cxx +++ b/Source/cmGeneratorExpressionParser.cxx @@ -6,6 +6,7 @@ #include <assert.h> #include <stddef.h> +#include <utility> cmGeneratorExpressionParser::cmGeneratorExpressionParser( const std::vector<cmGeneratorExpressionToken>& tokens) @@ -92,7 +93,7 @@ void cmGeneratorExpressionParser::ParseGeneratorExpression( assert(this->it != this->Tokens.end()); ++this->it; --this->NestingLevel; - content->SetIdentifier(identifier); + content->SetIdentifier(std::move(identifier)); result.push_back(content); return; } @@ -198,8 +199,8 @@ void cmGeneratorExpressionParser::ParseGeneratorExpression( ((this->it - 1)->Content - startToken->Content) + (this->it - 1)->Length; GeneratorExpressionContent* content = new GeneratorExpressionContent(startToken->Content, contentLength); - content->SetIdentifier(identifier); - content->SetParameters(parameters); + content->SetIdentifier(std::move(identifier)); + content->SetParameters(std::move(parameters)); result.push_back(content); } diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 2bb01b2..63bfbc6 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -132,8 +132,8 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg) this->SourceEntries, true); this->DLLPlatform = - (this->Makefile->IsOn("WIN32") || this->Makefile->IsOn("CYGWIN") || - this->Makefile->IsOn("MINGW")); + strcmp(this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"), + "") != 0; this->PolicyMap = t->PolicyMap; } @@ -240,13 +240,16 @@ const char* cmGeneratorTarget::GetOutputTargetType( case cmStateEnums::MODULE_LIBRARY: switch (artifact) { case cmStateEnums::RuntimeBinaryArtifact: - // Module import libraries are treated as archive targets. + // Module libraries are always treated as library targets. return "LIBRARY"; case cmStateEnums::ImportLibraryArtifact: - // Module libraries are always treated as library targets. + // Module import libraries are treated as archive targets. return "ARCHIVE"; } break; + case cmStateEnums::OBJECT_LIBRARY: + // Object libraries are always treated as object targets. + return "OBJECT"; case cmStateEnums::EXECUTABLE: switch (artifact) { case cmStateEnums::RuntimeBinaryArtifact: @@ -808,6 +811,26 @@ static void AddInterfaceEntries( } } +static void AddObjectEntries( + cmGeneratorTarget const* thisTarget, std::string const& config, + std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries) +{ + if (cmLinkImplementationLibraries const* impl = + thisTarget->GetLinkImplementationLibraries(config)) { + for (cmLinkImplItem const& lib : impl->Libraries) { + if (lib.Target && + lib.Target->GetType() == cmStateEnums::OBJECT_LIBRARY) { + std::string genex = "$<TARGET_OBJECTS:" + lib + ">"; + cmGeneratorExpression ge(lib.Backtrace); + std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex); + cge->SetEvaluateForBuildsystem(true); + entries.push_back( + new cmGeneratorTarget::TargetPropertyEntry(std::move(cge), lib)); + } + } + } +} + static bool processSources( cmGeneratorTarget const* tgt, const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, @@ -848,13 +871,10 @@ static bool processSources( std::ostringstream err; if (!targetName.empty()) { err << "Target \"" << targetName - << "\" contains relative " - "path in its INTERFACE_SOURCES:\n" - " \"" + << "\" contains relative path in its INTERFACE_SOURCES:\n \"" << src << "\""; } else { - err << "Found relative path while evaluating sources of " - "\"" + err << "Found relative path while evaluating sources of \"" << tgt->GetName() << "\":\n \"" << src << "\"\n"; } tgt->GetLocalGenerator()->IssueMessage(cmake::FATAL_ERROR, err.str()); @@ -931,23 +951,32 @@ void cmGeneratorTarget::GetSourceFiles(std::vector<std::string>& files, processSources(this, this->SourceEntries, files, uniqueSrcs, &dagChecker, config, debugSources); + // Collect INTERFACE_SOURCES of all direct link-dependencies. std::vector<cmGeneratorTarget::TargetPropertyEntry*> linkInterfaceSourcesEntries; - AddInterfaceEntries(this, config, "INTERFACE_SOURCES", linkInterfaceSourcesEntries); - std::vector<std::string>::size_type numFilesBefore = files.size(); bool contextDependentInterfaceSources = processSources(this, linkInterfaceSourcesEntries, files, uniqueSrcs, &dagChecker, config, debugSources); + // Collect TARGET_OBJECTS of direct object link-dependencies. + std::vector<cmGeneratorTarget::TargetPropertyEntry*> linkObjectsEntries; + AddObjectEntries(this, config, linkObjectsEntries); + std::vector<std::string>::size_type numFilesBefore2 = files.size(); + bool contextDependentObjects = + processSources(this, linkObjectsEntries, files, uniqueSrcs, &dagChecker, + config, debugSources); + if (!contextDependentDirectSources && - !(contextDependentInterfaceSources && numFilesBefore < files.size())) { + !(contextDependentInterfaceSources && numFilesBefore < files.size()) && + !(contextDependentObjects && numFilesBefore2 < files.size())) { this->LinkImplementationLanguageIsContextDependent = false; } cmDeleteAll(linkInterfaceSourcesEntries); + cmDeleteAll(linkObjectsEntries); } void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*>& files, @@ -1053,9 +1082,6 @@ void cmGeneratorTarget::ComputeKindedSources(KindedSources& files, kind = SourceKindHeader; } else if (sf->GetPropertyAsBool("EXTERNAL_OBJECT")) { kind = SourceKindExternalObject; - if (this->GetType() == cmStateEnums::OBJECT_LIBRARY) { - badObjLib.push_back(sf); - } } else if (!sf->GetLanguage().empty()) { kind = SourceKindObjectSource; } else if (ext == "def") { @@ -1673,6 +1699,7 @@ bool cmGeneratorTarget::HaveWellDefinedOutputFiles() const return this->GetType() == cmStateEnums::STATIC_LIBRARY || this->GetType() == cmStateEnums::SHARED_LIBRARY || this->GetType() == cmStateEnums::MODULE_LIBRARY || + this->GetType() == cmStateEnums::OBJECT_LIBRARY || this->GetType() == cmStateEnums::EXECUTABLE; } @@ -2001,8 +2028,13 @@ void cmGeneratorTarget::ComputeModuleDefinitionInfo( info.WindowsExportAllSymbols = this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS") && this->GetPropertyAsBool("WINDOWS_EXPORT_ALL_SYMBOLS"); +#if defined(_WIN32) && defined(CMAKE_BUILD_WITH_CMAKE) info.DefFileGenerated = info.WindowsExportAllSymbols || info.Sources.size() > 1; +#else + // Our __create_def helper is only available on Windows. + info.DefFileGenerated = false; +#endif if (info.DefFileGenerated) { info.DefFile = this->ObjectDirectory /* has slash */ + "exports.def"; } else if (!info.Sources.empty()) { @@ -2592,13 +2624,20 @@ std::vector<std::string> cmGeneratorTarget::GetIncludeDirectories( return includes; } +enum class OptionsParse +{ + None, + Shell +}; + static void processCompileOptionsInternal( cmGeneratorTarget const* tgt, const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, std::vector<std::string>& options, std::unordered_set<std::string>& uniqueOptions, cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config, - bool debugOptions, const char* logName, std::string const& language) + bool debugOptions, const char* logName, std::string const& language, + OptionsParse parse) { for (cmGeneratorTarget::TargetPropertyEntry* entry : entries) { std::vector<std::string> entryOptions; @@ -2609,7 +2648,12 @@ static void processCompileOptionsInternal( std::string usedOptions; for (std::string const& opt : entryOptions) { if (uniqueOptions.insert(opt).second) { - options.push_back(opt); + if (parse == OptionsParse::Shell && + cmHasLiteralPrefix(opt, "SHELL:")) { + cmSystemTools::ParseUnixCommandLine(opt.c_str() + 6, options); + } else { + options.push_back(opt); + } if (debugOptions) { usedOptions += " * " + opt + "\n"; } @@ -2634,7 +2678,7 @@ static void processCompileOptions( { processCompileOptionsInternal(tgt, entries, options, uniqueOptions, dagChecker, config, debugOptions, "options", - language); + language, OptionsParse::Shell); } void cmGeneratorTarget::GetCompileOptions(std::vector<std::string>& result, @@ -2688,7 +2732,7 @@ static void processCompileFeatures( { processCompileOptionsInternal(tgt, entries, options, uniqueOptions, dagChecker, config, debugOptions, "features", - std::string()); + std::string(), OptionsParse::None); } void cmGeneratorTarget::GetCompileFeatures(std::vector<std::string>& result, @@ -2738,7 +2782,7 @@ static void processCompileDefinitions( { processCompileOptionsInternal(tgt, entries, options, uniqueOptions, dagChecker, config, debugOptions, - "definitions", language); + "definitions", language, OptionsParse::None); } void cmGeneratorTarget::GetCompileDefinitions( @@ -5325,20 +5369,6 @@ cmGeneratorTarget* cmGeneratorTarget::FindTargetToLink( tgt = nullptr; } - if (tgt && tgt->GetType() == cmStateEnums::OBJECT_LIBRARY) { - std::ostringstream e; - e << "Target \"" << this->GetName() << "\" links to " - "OBJECT library \"" - << tgt->GetName() - << "\" but this is not " - "allowed. " - "One may link only to STATIC or SHARED libraries, or to executables " - "with the ENABLE_EXPORTS property set."; - cmake* cm = this->LocalGenerator->GetCMakeInstance(); - cm->IssueMessage(cmake::FATAL_ERROR, e.str(), this->GetBacktrace()); - tgt = nullptr; - } - return tgt; } @@ -5402,6 +5432,7 @@ bool cmGeneratorTarget::IsLinkable() const this->GetType() == cmStateEnums::SHARED_LIBRARY || this->GetType() == cmStateEnums::MODULE_LIBRARY || this->GetType() == cmStateEnums::UNKNOWN_LIBRARY || + this->GetType() == cmStateEnums::OBJECT_LIBRARY || this->GetType() == cmStateEnums::INTERFACE_LIBRARY || this->IsExecutableWithExports()); } diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index c805b98..f9eb90f 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -6,11 +6,11 @@ #include "cmsys/FStream.hxx" #include <algorithm> #include <assert.h> +#include <cstring> #include <iterator> #include <sstream> #include <stdio.h> #include <stdlib.h> -#include <string.h> #if defined(_WIN32) && !defined(__CYGWIN__) #include <windows.h> @@ -1806,6 +1806,8 @@ int cmGlobalGenerator::Build(const std::string& /*unused*/, cmSystemTools::OutputOption outputflag, std::vector<std::string> const& nativeOptions) { + bool hideconsole = cmSystemTools::GetRunCommandHideConsole(); + /** * Run an executable command and put the stdout in output. */ @@ -1813,9 +1815,17 @@ int cmGlobalGenerator::Build(const std::string& /*unused*/, output += "Change Dir: "; output += bindir; output += "\n"; + if (workdir.Failed()) { + cmSystemTools::SetRunCommandHideConsole(hideconsole); + cmSystemTools::Error("Failed to change directory: ", + std::strerror(workdir.GetLastResult())); + output += "Failed to change directory: "; + output += std::strerror(workdir.GetLastResult()); + output += "\n"; + return 1; + } int retVal; - bool hideconsole = cmSystemTools::GetRunCommandHideConsole(); cmSystemTools::SetRunCommandHideConsole(true); std::string outputBuffer; std::string* outputPtr = &outputBuffer; diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index b251f86..55a403e 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -1223,11 +1223,13 @@ void cmGlobalNinjaGenerator::WriteUnknownExplicitDependencies(std::ostream& os) for (std::string const& file : files) { knownDependencies.insert(this->ConvertToNinjaPath(file)); } - // get list files which are implicit dependencies as well and will be phony - // for rebuild manifest - std::vector<std::string> const& lf = lg->GetMakefile()->GetListFiles(); - for (std::string const& j : lf) { - knownDependencies.insert(this->ConvertToNinjaPath(j)); + if (!this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) { + // get list files which are implicit dependencies as well and will be + // phony for rebuild manifest + std::vector<std::string> const& lf = lg->GetMakefile()->GetListFiles(); + for (std::string const& j : lf) { + knownDependencies.insert(this->ConvertToNinjaPath(j)); + } } std::vector<cmGeneratorExpressionEvaluationFile*> const& ef = lg->GetMakefile()->GetEvaluationFiles(); @@ -1335,6 +1337,9 @@ void cmGlobalNinjaGenerator::WriteTargetAll(std::ostream& os) void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) { + if (this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) { + return; + } cmLocalGenerator* lg = this->LocalGenerators[0]; std::ostringstream cmd; @@ -1384,8 +1389,14 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) /*explicitDeps=*/cmNinjaDeps(), implicitDeps, /*orderOnlyDeps=*/cmNinjaDeps(), variables); + cmNinjaDeps missingInputs; + std::set_difference(std::make_move_iterator(implicitDeps.begin()), + std::make_move_iterator(implicitDeps.end()), + CustomCommandOutputs.begin(), CustomCommandOutputs.end(), + std::back_inserter(missingInputs)); + this->WritePhonyBuild(os, "A missing CMake input file is not an error.", - implicitDeps, cmNinjaDeps()); + missingInputs, cmNinjaDeps()); } std::string cmGlobalNinjaGenerator::ninjaCmd() const diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index d990a6c..c92df55 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -241,6 +241,10 @@ void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2() lg->WriteMakeRule(makefileStream, "The main recursive preinstall target", "preinstall", depends, no_commands, true); + // Write an empty clean: + lg->WriteMakeRule(makefileStream, "The main recursive clean target", "clean", + depends, no_commands, true); + // Write out the "special" stuff lg->WriteSpecialTargetsTop(makefileStream); @@ -256,6 +260,10 @@ void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2() void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() { + if (this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) { + return; + } + // Open the output file. This should not be copy-if-different // because the check-build-system step compares the makefile time to // see if the build system must be regenerated. @@ -525,7 +533,10 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules( std::vector<std::string> depends; std::vector<std::string> commands; - depends.push_back("cmake_check_build_system"); + bool regenerate = !this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION"); + if (regenerate) { + depends.push_back("cmake_check_build_system"); + } // write the target convenience rules for (cmLocalGenerator* localGen : this->LocalGenerators) { @@ -558,7 +569,9 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules( tmp += "Makefile2"; commands.push_back(lg->GetRecursiveMakeCall(tmp.c_str(), name)); depends.clear(); - depends.push_back("cmake_check_build_system"); + if (regenerate) { + depends.push_back("cmake_check_build_system"); + } lg->WriteMakeRule(ruleFileStream, "Build rule for target.", name, depends, commands, true); @@ -609,7 +622,10 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( // write the directory level rules for this local gen this->WriteDirectoryRules2(ruleFileStream, lg); - depends.push_back("cmake_check_build_system"); + bool regenerate = !this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION"); + if (regenerate) { + depends.push_back("cmake_check_build_system"); + } // for each target Generate the rule files for each target. const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets(); @@ -715,7 +731,9 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( commands.push_back(progCmd.str()); } depends.clear(); - depends.push_back("cmake_check_build_system"); + if (regenerate) { + depends.push_back("cmake_check_build_system"); + } localName = lg->GetRelativeTargetDirectory(gtarget); localName += "/rule"; lg->WriteMakeRule(ruleFileStream, @@ -898,7 +916,9 @@ void cmGlobalUnixMakefileGenerator3::WriteHelpRule( "for this Makefile:"); lg->AppendEcho(commands, "... all (the default if no target is provided)"); lg->AppendEcho(commands, "... clean"); - lg->AppendEcho(commands, "... depend"); + if (!this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) { + lg->AppendEcho(commands, "... depend"); + } // Keep track of targets already listed. std::set<std::string> emittedTargets; diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index 73a5dae..205e0d0 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -636,126 +636,89 @@ bool cmGlobalVisualStudio10Generator::FindVCTargetsPath(cmMakefile* mf) cmsys::ofstream fout(vcxprojAbs.c_str()); cmXMLWriter xw(fout); - /* clang-format off */ - xw.StartDocument(); - xw.StartElement("Project"); - xw.Attribute("DefaultTargets", "Build"); - xw.Attribute("ToolsVersion", "4.0"); - xw.Attribute("xmlns", - "http://schemas.microsoft.com/developer/msbuild/2003"); - if (this->IsNsightTegra()) { - xw.StartElement("PropertyGroup"); - xw.Attribute("Label", "NsightTegraProject"); - xw.StartElement("NsightTegraProjectRevisionNumber"); - xw.Content("6"); - xw.EndElement(); // NsightTegraProjectRevisionNumber - xw.EndElement(); // PropertyGroup - } - xw.StartElement("ItemGroup"); - xw.Attribute("Label", "ProjectConfigurations"); - xw.StartElement("ProjectConfiguration"); - xw.Attribute("Include", "Debug|" + this->GetPlatformName()); - xw.StartElement("Configuration"); - xw.Content("Debug"); - xw.EndElement(); // Configuration - xw.StartElement("Platform"); - xw.Content(this->GetPlatformName()); - xw.EndElement(); // Platform - xw.EndElement(); // ProjectConfiguration - xw.EndElement(); // ItemGroup - xw.StartElement("PropertyGroup"); - xw.Attribute("Label", "Globals"); - xw.StartElement("ProjectGuid"); - xw.Content("{F3FC6D86-508D-3FB1-96D2-995F08B142EC}"); - xw.EndElement(); // ProjectGuid - xw.StartElement("Keyword"); - xw.Content("Win32Proj"); - xw.EndElement(); // Keyword - xw.StartElement("Platform"); - xw.Content(this->GetPlatformName()); - xw.EndElement(); // Platform - if (this->GetSystemName() == "WindowsPhone") { - xw.StartElement("ApplicationType"); - xw.Content("Windows Phone"); - xw.EndElement(); // ApplicationType - xw.StartElement("ApplicationTypeRevision"); - xw.Content(this->GetSystemVersion()); - xw.EndElement(); // ApplicationTypeRevision - } else if (this->GetSystemName() == "WindowsStore") { - xw.StartElement("ApplicationType"); - xw.Content("Windows Store"); - xw.EndElement(); // ApplicationType - xw.StartElement("ApplicationTypeRevision"); - xw.Content(this->GetSystemVersion()); - xw.EndElement(); // ApplicationTypeRevision - } - if (!this->WindowsTargetPlatformVersion.empty()) { - xw.StartElement("WindowsTargetPlatformVersion"); - xw.Content(this->WindowsTargetPlatformVersion); - xw.EndElement(); // WindowsTargetPlatformVersion - } - if (this->GetPlatformName() == "ARM64") { - xw.StartElement("WindowsSDKDesktopARM64Support"); - xw.Content("true"); - xw.EndElement(); // WindowsSDK64DesktopARMSupport - } - else if (this->GetPlatformName() == "ARM") { - xw.StartElement("WindowsSDKDesktopARMSupport"); - xw.Content("true"); - xw.EndElement(); // WindowsSDKDesktopARMSupport - } - xw.EndElement(); // PropertyGroup - xw.StartElement("Import"); - xw.Attribute("Project", - "$(VCTargetsPath)\\Microsoft.Cpp.Default.props"); - xw.EndElement(); // Import + cmXMLDocument doc(xw); + cmXMLElement eprj(doc, "Project"); + eprj.Attribute("DefaultTargets", "Build"); + eprj.Attribute("ToolsVersion", "4.0"); + eprj.Attribute("xmlns", + "http://schemas.microsoft.com/developer/msbuild/2003"); + if (this->IsNsightTegra()) { + cmXMLElement epg(eprj, "PropertyGroup"); + epg.Attribute("Label", "NsightTegraProject"); + cmXMLElement(epg, "NsightTegraProjectRevisionNumber").Content("6"); + } + { + cmXMLElement eig(eprj, "ItemGroup"); + eig.Attribute("Label", "ProjectConfigurations"); + cmXMLElement epc(eig, "ProjectConfiguration"); + epc.Attribute("Include", "Debug|" + this->GetPlatformName()); + cmXMLElement(epc, "Configuration").Content("Debug"); + cmXMLElement(epc, "Platform").Content(this->GetPlatformName()); + } + { + cmXMLElement epg(eprj, "PropertyGroup"); + epg.Attribute("Label", "Globals"); + cmXMLElement(epg, "ProjectGuid") + .Content("{F3FC6D86-508D-3FB1-96D2-995F08B142EC}"); + cmXMLElement(epg, "Keyword").Content("Win32Proj"); + cmXMLElement(epg, "Platform").Content(this->GetPlatformName()); + if (this->GetSystemName() == "WindowsPhone") { + cmXMLElement(epg, "ApplicationType").Content("Windows Phone"); + cmXMLElement(epg, "ApplicationTypeRevision") + .Content(this->GetSystemVersion()); + } else if (this->GetSystemName() == "WindowsStore") { + cmXMLElement(epg, "ApplicationType").Content("Windows Store"); + cmXMLElement(epg, "ApplicationTypeRevision") + .Content(this->GetSystemVersion()); + } + if (!this->WindowsTargetPlatformVersion.empty()) { + cmXMLElement(epg, "WindowsTargetPlatformVersion") + .Content(this->WindowsTargetPlatformVersion); + } + if (this->GetPlatformName() == "ARM64") { + cmXMLElement(epg, "WindowsSDKDesktopARM64Support").Content("true"); + } else if (this->GetPlatformName() == "ARM") { + cmXMLElement(epg, "WindowsSDKDesktopARMSupport").Content("true"); + } + } + cmXMLElement(eprj, "Import") + .Attribute("Project", "$(VCTargetsPath)\\Microsoft.Cpp.Default.props"); if (!this->GeneratorToolsetHostArchitecture.empty()) { - xw.StartElement("PropertyGroup"); - xw.StartElement("PreferredToolArchitecture"); - xw.Content(this->GeneratorToolsetHostArchitecture); - xw.EndElement(); // PreferredToolArchitecture - xw.EndElement(); // PropertyGroup + cmXMLElement epg(eprj, "PropertyGroup"); + cmXMLElement(epg, "PreferredToolArchitecture") + .Content(this->GeneratorToolsetHostArchitecture); } - xw.StartElement("PropertyGroup"); - xw.Attribute("Label", "Configuration"); - xw.StartElement("ConfigurationType"); + { + cmXMLElement epg(eprj, "PropertyGroup"); + epg.Attribute("Label", "Configuration"); + { + cmXMLElement ect(epg, "ConfigurationType"); + if (this->IsNsightTegra()) { + // Tegra-Android platform does not understand "Utility". + ect.Content("StaticLibrary"); + } else { + ect.Content("Utility"); + } + } + cmXMLElement(epg, "CharacterSet").Content("MultiByte"); if (this->IsNsightTegra()) { - // Tegra-Android platform does not understand "Utility". - xw.Content("StaticLibrary"); + cmXMLElement(epg, "NdkToolchainVersion") + .Content(this->GetPlatformToolsetString()); } else { - xw.Content("Utility"); + cmXMLElement(epg, "PlatformToolset") + .Content(this->GetPlatformToolsetString()); } - xw.EndElement(); // ConfigurationType - xw.StartElement("CharacterSet"); - xw.Content("MultiByte"); - xw.EndElement(); // CharacterSet - if (this->IsNsightTegra()) { - xw.StartElement("NdkToolchainVersion"); - xw.Content(this->GetPlatformToolsetString()); - xw.EndElement(); // NdkToolchainVersion - } else { - xw.StartElement("PlatformToolset"); - xw.Content(this->GetPlatformToolsetString()); - xw.EndElement(); // PlatformToolset - } - xw.EndElement(); // PropertyGroup - xw.StartElement("Import"); - xw.Attribute("Project", "$(VCTargetsPath)\\Microsoft.Cpp.props"); - xw.EndElement(); // Import - xw.StartElement("ItemDefinitionGroup"); - xw.StartElement("PostBuildEvent"); - xw.StartElement("Command"); - xw.Content("echo VCTargetsPath=$(VCTargetsPath)"); - xw.EndElement(); // Command - xw.EndElement(); // PostBuildEvent - xw.EndElement(); // ItemDefinitionGroup - xw.StartElement("Import"); - xw.Attribute("Project", - "$(VCTargetsPath)\\Microsoft.Cpp.targets"); - xw.EndElement(); // Import - xw.EndElement(); // Project - xw.EndDocument(); - /* clang-format on */ + } + cmXMLElement(eprj, "Import") + .Attribute("Project", "$(VCTargetsPath)\\Microsoft.Cpp.props"); + { + cmXMLElement eidg(eprj, "ItemDefinitionGroup"); + cmXMLElement epbe(eidg, "PostBuildEvent"); + cmXMLElement(epbe, "Command") + .Content("echo VCTargetsPath=$(VCTargetsPath)"); + } + cmXMLElement(eprj, "Import") + .Attribute("Project", "$(VCTargetsPath)\\Microsoft.Cpp.targets"); } std::vector<std::string> cmd; diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index c915dc5..7ff007f 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -294,19 +294,6 @@ void cmGlobalVisualStudio7Generator::Generate() if (!cmSystemTools::GetErrorOccuredFlag()) { this->CallVisualStudioMacro(MacroReload); } - - if (this->Version == VS8 && !this->CMakeInstance->GetIsInTryCompile()) { - const char* cmakeWarnVS8 = - this->CMakeInstance->GetState()->GetCacheEntryValue("CMAKE_WARN_VS8"); - if (!cmakeWarnVS8 || !cmSystemTools::IsOff(cmakeWarnVS8)) { - this->CMakeInstance->IssueMessage( - cmake::WARNING, - "The \"Visual Studio 8 2005\" generator is deprecated " - "and will be removed in a future version of CMake." - "\n" - "Add CMAKE_WARN_VS8=OFF to the cache to disable this warning."); - } - } } void cmGlobalVisualStudio7Generator::OutputSLNFile( diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx index ab8ad70..ad72f5e 100644 --- a/Source/cmGlobalVisualStudio8Generator.cxx +++ b/Source/cmGlobalVisualStudio8Generator.cxx @@ -11,75 +11,6 @@ #include "cmVisualStudioWCEPlatformParser.h" #include "cmake.h" -static const char vs8generatorName[] = "Visual Studio 8 2005"; - -class cmGlobalVisualStudio8Generator::Factory : public cmGlobalGeneratorFactory -{ -public: - cmGlobalGenerator* CreateGlobalGenerator(const std::string& name, - cmake* cm) const override - { - if (strncmp(name.c_str(), vs8generatorName, - sizeof(vs8generatorName) - 1) != 0) { - return 0; - } - - const char* p = name.c_str() + sizeof(vs8generatorName) - 1; - if (p[0] == '\0') { - return new cmGlobalVisualStudio8Generator(cm, name, ""); - } - - if (p[0] != ' ') { - return 0; - } - - ++p; - - if (!strcmp(p, "Win64")) { - return new cmGlobalVisualStudio8Generator(cm, name, "x64"); - } - - cmVisualStudioWCEPlatformParser parser(p); - parser.ParseVersion("8.0"); - if (!parser.Found()) { - return 0; - } - - cmGlobalVisualStudio8Generator* ret = - new cmGlobalVisualStudio8Generator(cm, name, p); - ret->WindowsCEVersion = parser.GetOSVersion(); - return ret; - } - - void GetDocumentation(cmDocumentationEntry& entry) const override - { - entry.Name = std::string(vs8generatorName) + " [arch]"; - entry.Brief = "Deprecated. Generates Visual Studio 2005 project files. " - "Optional [arch] can be \"Win64\"."; - } - - void GetGenerators(std::vector<std::string>& names) const override - { - names.push_back(vs8generatorName); - names.push_back(vs8generatorName + std::string(" Win64")); - cmVisualStudioWCEPlatformParser parser; - parser.ParseVersion("8.0"); - const std::vector<std::string>& availablePlatforms = - parser.GetAvailablePlatforms(); - for (std::string const& i : availablePlatforms) { - names.push_back("Visual Studio 8 2005 " + i); - } - } - - bool SupportsToolset() const override { return false; } - bool SupportsPlatform() const override { return true; } -}; - -cmGlobalGeneratorFactory* cmGlobalVisualStudio8Generator::NewFactory() -{ - return new Factory; -} - cmGlobalVisualStudio8Generator::cmGlobalVisualStudio8Generator( cmake* cm, const std::string& name, const std::string& platformName) : cmGlobalVisualStudio71Generator(cm, platformName) @@ -87,12 +18,6 @@ cmGlobalVisualStudio8Generator::cmGlobalVisualStudio8Generator( this->ProjectConfigurationSectionName = "ProjectConfigurationPlatforms"; this->Name = name; this->ExtraFlagTable = this->GetExtraFlagTableVS8(); - this->Version = VS8; - std::string vc8Express; - this->ExpressEdition = cmSystemTools::ReadRegistryValue( - "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\8.0\\Setup\\VC;" - "ProductDir", - vc8Express, cmSystemTools::KeyWOW64_32); } std::string cmGlobalVisualStudio8Generator::FindDevEnvCommand() @@ -143,13 +68,6 @@ bool cmGlobalVisualStudio8Generator::SetGeneratorPlatform(std::string const& p, } } -// output standard header for dsw file -void cmGlobalVisualStudio8Generator::WriteSLNHeader(std::ostream& fout) -{ - fout << "Microsoft Visual Studio Solution File, Format Version 9.00\n"; - fout << "# Visual Studio 2005\n"; -} - std::string cmGlobalVisualStudio8Generator::GetGenerateStampList() { return "generate.stamp.list"; @@ -165,46 +83,6 @@ bool cmGlobalVisualStudio8Generator::UseFolderProperty() return IsExpressEdition() ? false : cmGlobalGenerator::UseFolderProperty(); } -std::string cmGlobalVisualStudio8Generator::GetUserMacrosDirectory() -{ - // Some VS8 sp0 versions cannot run macros. - // See http://support.microsoft.com/kb/928209 - const char* vc8sp1Registry = - "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\" - "InstalledProducts\\KB926601;"; - const char* vc8exSP1Registry = - "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\" - "InstalledProducts\\KB926748;"; - std::string vc8sp1; - if (!cmSystemTools::ReadRegistryValue(vc8sp1Registry, vc8sp1) && - !cmSystemTools::ReadRegistryValue(vc8exSP1Registry, vc8sp1)) { - return ""; - } - - std::string base; - std::string path; - - // base begins with the VisualStudioProjectsLocation reg value... - if (cmSystemTools::ReadRegistryValue( - "HKEY_CURRENT_USER\\Software\\Microsoft\\VisualStudio\\8.0;" - "VisualStudioProjectsLocation", - base)) { - cmSystemTools::ConvertToUnixSlashes(base); - - // 8.0 macros folder: - path = base + "/VSMacros80"; - } - - // path is (correctly) still empty if we did not read the base value from - // the Registry value - return path; -} - -std::string cmGlobalVisualStudio8Generator::GetUserMacrosRegKeyBase() -{ - return "Software\\Microsoft\\VisualStudio\\8.0\\vsmacros"; -} - bool cmGlobalVisualStudio8Generator::AddCheckTarget() { // Add a special target on which all other targets depend that @@ -217,7 +95,7 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() cmMakefile* mf = lg->GetMakefile(); // Skip the target if no regeneration is to be done. - if (mf->IsOn("CMAKE_SUPPRESS_REGENERATION")) { + if (this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) { return false; } diff --git a/Source/cmGlobalVisualStudio8Generator.h b/Source/cmGlobalVisualStudio8Generator.h index af83e4f..6f64b9c 100644 --- a/Source/cmGlobalVisualStudio8Generator.h +++ b/Source/cmGlobalVisualStudio8Generator.h @@ -15,7 +15,6 @@ class cmGlobalVisualStudio8Generator : public cmGlobalVisualStudio71Generator public: cmGlobalVisualStudio8Generator(cmake* cm, const std::string& name, const std::string& platformName); - static cmGlobalGeneratorFactory* NewFactory(); ///! Get the name for the generator. std::string GetName() const override { return this->Name; } @@ -35,19 +34,6 @@ public: */ 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. - */ - std::string GetUserMacrosDirectory() override; - - /** - * What is the reg key path to "vsmacros" for this version of Visual - * Studio? - */ - std::string GetUserMacrosRegKeyBase() override; - /** Return true if the target project file should have the option LinkLibraryDependencies and link to .sln dependencies. */ bool NeedLinkLibraryDependencies(cmGeneratorTarget* target) override; @@ -75,7 +61,6 @@ protected: virtual bool NeedsDeploy(cmStateEnums::TargetType type) const; static cmIDEFlagTable const* GetExtraFlagTableVS8(); - void WriteSLNHeader(std::ostream& fout) override; void WriteSolutionConfigurations( std::ostream& fout, std::vector<std::string> const& configs) override; void WriteProjectConfigurations( @@ -93,9 +78,5 @@ protected: std::string Name; std::string WindowsCEVersion; bool ExpressEdition; - -private: - class Factory; - friend class Factory; }; #endif diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index a4570e1..fa7dc51 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -737,26 +737,24 @@ bool cmGlobalVisualStudioGenerator::TargetIsFortranOnly( bool cmGlobalVisualStudioGenerator::TargetIsCSharpOnly( cmGeneratorTarget const* gt) { - // check to see if this is a C# build - std::set<std::string> languages; - { - // Issue diagnostic if the source files depend on the config. - std::vector<cmSourceFile*> sources; - if (!gt->GetConfigCommonSourceFiles(sources)) { - return false; - } - // Only "real" targets are allowed to be C# targets. - if (gt->Target->GetType() > cmStateEnums::OBJECT_LIBRARY) { - return false; - } + // C# targets can be defined with add_library() (using SHARED or STATIC) and + // also using add_executable(). We do not treat imported C# targets the same + // (these come in as UTILITY) + if (gt->GetType() != cmStateEnums::SHARED_LIBRARY && + gt->GetType() != cmStateEnums::STATIC_LIBRARY && + gt->GetType() != cmStateEnums::EXECUTABLE) { + return false; } - gt->GetLanguages(languages, ""); - if (languages.size() == 1) { - if (*languages.begin() == "CSharp") { - return true; - } + + // Issue diagnostic if the source files depend on the config. + std::vector<cmSourceFile*> sources; + if (!gt->GetConfigCommonSourceFiles(sources)) { + return false; } - return false; + + std::set<std::string> languages; + gt->GetLanguages(languages, ""); + return languages.size() == 1 && languages.count("CSharp") > 0; } bool cmGlobalVisualStudioGenerator::TargetCanBeReferenced( diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h index 75b7f22..f39dcca 100644 --- a/Source/cmGlobalVisualStudioGenerator.h +++ b/Source/cmGlobalVisualStudioGenerator.h @@ -32,7 +32,6 @@ public: /** Known versions of Visual Studio. */ enum VSVersion { - VS8 = 80, VS9 = 90, VS10 = 100, VS11 = 110, diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 8f61071..f8597af 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -458,7 +458,7 @@ void cmGlobalXCodeGenerator::AddExtraTargets( makeHelper.push_back(""); // placeholder, see below // Add ZERO_CHECK - bool regenerate = !mf->IsOn("CMAKE_SUPPRESS_REGENERATION"); + bool regenerate = !this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION"); bool generateTopLevelProjectOnly = mf->IsOn("CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY"); bool isTopLevel = @@ -466,7 +466,7 @@ void cmGlobalXCodeGenerator::AddExtraTargets( if (regenerate && (isTopLevel || !generateTopLevelProjectOnly)) { this->CreateReRunCMakeFile(root, gens); std::string file = - this->ConvertToRelativeForMake(this->CurrentReRunCMakeMakefile.c_str()); + this->ConvertToRelativeForMake(this->CurrentReRunCMakeMakefile); cmSystemTools::ReplaceString(file, "\\ ", " "); cmTarget* check = mf->AddUtilityCommand( CMAKE_CHECK_BUILD_SYSTEM_TARGET, cmMakefile::TargetOrigin::Generator, @@ -553,7 +553,7 @@ void cmGlobalXCodeGenerator::CreateReRunCMakeFile( for (const auto& lfile : lfiles) { makefileStream << "TARGETS += $(subst $(space),$(spaceplus),$(wildcard " - << this->ConvertToRelativeForMake(lfile.c_str()) << "))\n"; + << this->ConvertToRelativeForMake(lfile) << "))\n"; } std::string checkCache = root->GetBinaryDirectory(); @@ -562,11 +562,11 @@ void cmGlobalXCodeGenerator::CreateReRunCMakeFile( checkCache += "cmake.check_cache"; makefileStream << "\n" - << this->ConvertToRelativeForMake(checkCache.c_str()) + << this->ConvertToRelativeForMake(checkCache) << ": $(TARGETS)\n"; makefileStream << "\t" << this->ConvertToRelativeForMake( - cmSystemTools::GetCMakeCommand().c_str()) + cmSystemTools::GetCMakeCommand()) << " -H" << this->ConvertToRelativeForMake(root->GetSourceDirectory()) << " -B" @@ -1571,12 +1571,11 @@ void cmGlobalXCodeGenerator::AddCommandsToBuildPhase( } std::string cdir = this->CurrentLocalGenerator->GetCurrentBinaryDirectory(); - cdir = this->ConvertToRelativeForMake(cdir.c_str()); + cdir = this->ConvertToRelativeForMake(cdir); std::string makecmd = "make -C "; makecmd += cdir; makecmd += " -f "; - makecmd += - this->ConvertToRelativeForMake((makefile + "$CONFIGURATION").c_str()); + makecmd += this->ConvertToRelativeForMake((makefile + "$CONFIGURATION")); makecmd += " all"; buildphase->AddAttribute("shellScript", this->CreateString(makecmd)); buildphase->AddAttribute("showEnvVarsInLog", this->CreateString("0")); @@ -1611,8 +1610,7 @@ void cmGlobalXCodeGenerator::CreateCustomRulesMakefile( const std::vector<std::string>& outputs = ccg.GetOutputs(); if (!outputs.empty()) { for (auto const& output : outputs) { - makefileStream << "\\\n\t" - << this->ConvertToRelativeForMake(output.c_str()); + makefileStream << "\\\n\t" << this->ConvertToRelativeForMake(output); } } else { std::ostringstream str; @@ -1633,8 +1631,7 @@ void cmGlobalXCodeGenerator::CreateCustomRulesMakefile( // There is at least one output, start the rule for it const char* sep = ""; for (auto const& output : outputs) { - makefileStream << sep - << this->ConvertToRelativeForMake(output.c_str()); + makefileStream << sep << this->ConvertToRelativeForMake(output); sep = " "; } makefileStream << ": "; @@ -1646,8 +1643,7 @@ void cmGlobalXCodeGenerator::CreateCustomRulesMakefile( std::string dep; if (this->CurrentLocalGenerator->GetRealDependency(d, configName, dep)) { - makefileStream << "\\\n" - << this->ConvertToRelativeForMake(dep.c_str()); + makefileStream << "\\\n" << this->ConvertToRelativeForMake(dep); } } makefileStream << "\n"; @@ -1664,12 +1660,12 @@ void cmGlobalXCodeGenerator::CreateCustomRulesMakefile( // Build the command line in a single string. std::string cmd2 = ccg.GetCommand(c); cmSystemTools::ReplaceString(cmd2, "/./", "/"); - cmd2 = this->ConvertToRelativeForMake(cmd2.c_str()); + cmd2 = this->ConvertToRelativeForMake(cmd2); std::string cmd; std::string wd = ccg.GetWorkingDirectory(); if (!wd.empty()) { cmd += "cd "; - cmd += this->ConvertToRelativeForMake(wd.c_str()); + cmd += this->ConvertToRelativeForMake(wd); cmd += " && "; } cmd += cmd2; @@ -3193,7 +3189,7 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget( gt->GetType() == cmStateEnums::SHARED_LIBRARY || gt->GetType() == cmStateEnums::MODULE_LIBRARY) { std::string tfull = gt->GetFullPath(configName); - std::string trel = this->ConvertToRelativeForMake(tfull.c_str()); + std::string trel = this->ConvertToRelativeForMake(tfull); // Add this target to the post-build phases of its dependencies. std::map<std::string, cmXCodeObject::StringVec>::const_iterator y = @@ -3221,7 +3217,7 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget( target->GetDependLibraries().find(configName); if (x != target->GetDependLibraries().end()) { for (auto const& deplib : x->second) { - std::string file = this->ConvertToRelativeForMake(deplib.c_str()); + std::string file = this->ConvertToRelativeForMake(deplib); makefileStream << "\\\n\t" << file; dummyRules.insert(file); } @@ -3236,7 +3232,7 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget( d += objLibName; d += ".a"; - std::string dependency = this->ConvertToRelativeForMake(d.c_str()); + std::string dependency = this->ConvertToRelativeForMake(d); makefileStream << "\\\n\t" << dependency; dummyRules.insert(dependency); } @@ -3244,8 +3240,7 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget( // Write the action to remove the target if it is out of date. makefileStream << "\n"; makefileStream << "\t/bin/rm -f " - << this->ConvertToRelativeForMake(tfull.c_str()) - << "\n"; + << this->ConvertToRelativeForMake(tfull) << "\n"; // if building for more than one architecture // then remove those executables as well if (this->Architectures.size() > 1) { @@ -3257,8 +3252,7 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget( universalFile += "/"; universalFile += gt->GetFullName(configName); makefileStream << "\t/bin/rm -f " - << this->ConvertToRelativeForMake( - universalFile.c_str()) + << this->ConvertToRelativeForMake(universalFile) << "\n"; } } diff --git a/Source/cmIDEOptions.cxx b/Source/cmIDEOptions.cxx index 354b757..f996788 100644 --- a/Source/cmIDEOptions.cxx +++ b/Source/cmIDEOptions.cxx @@ -25,7 +25,7 @@ cmIDEOptions::~cmIDEOptions() { } -void cmIDEOptions::HandleFlag(const char* flag) +void cmIDEOptions::HandleFlag(std::string const& flag) { // If the last option was -D then this option is the definition. if (this->DoingDefine) { @@ -49,26 +49,27 @@ void cmIDEOptions::HandleFlag(const char* flag) } // Look for known arguments. - if (flag[0] == '-' || (this->AllowSlash && flag[0] == '/')) { + size_t len = flag.length(); + if (len > 0 && (flag[0] == '-' || (this->AllowSlash && flag[0] == '/'))) { // Look for preprocessor definitions. - if (this->AllowDefine && flag[1] == 'D') { - if (flag[2] == '\0') { + if (this->AllowDefine && len > 1 && flag[1] == 'D') { + if (len <= 2) { // The next argument will have the definition. this->DoingDefine = true; } else { // Store this definition. - this->Defines.push_back(flag + 2); + this->Defines.push_back(flag.substr(2)); } return; } // Look for include directory. - if (this->AllowInclude && flag[1] == 'I') { - if (flag[2] == '\0') { + if (this->AllowInclude && len > 1 && flag[1] == 'I') { + if (len <= 2) { // The next argument will have the include directory. this->DoingInclude = true; } else { // Store this include directory. - this->Includes.push_back(flag + 2); + this->Includes.push_back(flag.substr(2)); } return; } @@ -92,8 +93,9 @@ void cmIDEOptions::HandleFlag(const char* flag) } bool cmIDEOptions::CheckFlagTable(cmIDEFlagTable const* table, - const char* flag, bool& flag_handled) + std::string const& flag, bool& flag_handled) { + const char* pf = flag.c_str() + 1; // Look for an entry in the flag table matching this flag. for (cmIDEFlagTable const* entry = table; entry->IDEName; ++entry) { bool entry_found = false; @@ -102,17 +104,17 @@ bool cmIDEOptions::CheckFlagTable(cmIDEFlagTable const* table, // the entry specifies UserRequired we must match only if a // non-empty value is given. int n = static_cast<int>(strlen(entry->commandFlag)); - if ((strncmp(flag + 1, entry->commandFlag, n) == 0 || + if ((strncmp(pf, entry->commandFlag, n) == 0 || (entry->special & cmIDEFlagTable::CaseInsensitive && - cmsysString_strncasecmp(flag + 1, entry->commandFlag, n))) && + cmsysString_strncasecmp(pf, entry->commandFlag, n))) && (!(entry->special & cmIDEFlagTable::UserRequired) || - static_cast<int>(strlen(flag + 1)) > n)) { - this->FlagMapUpdate(entry, flag + n + 1); + static_cast<int>(strlen(pf)) > n)) { + this->FlagMapUpdate(entry, std::string(pf + n)); entry_found = true; } - } else if (strcmp(flag + 1, entry->commandFlag) == 0 || + } else if (strcmp(pf, entry->commandFlag) == 0 || (entry->special & cmIDEFlagTable::CaseInsensitive && - cmsysString_strcasecmp(flag + 1, entry->commandFlag) == 0)) { + cmsysString_strcasecmp(pf, entry->commandFlag) == 0)) { if (entry->special & cmIDEFlagTable::UserFollowing) { // This flag expects a value in the following argument. this->DoingFollowing = entry; @@ -137,7 +139,7 @@ bool cmIDEOptions::CheckFlagTable(cmIDEFlagTable const* table, } void cmIDEOptions::FlagMapUpdate(cmIDEFlagTable const* entry, - const char* new_value) + std::string const& new_value) { if (entry->special & cmIDEFlagTable::UserIgnored) { // Ignore the user-specified value. @@ -157,9 +159,9 @@ void cmIDEOptions::AddDefine(const std::string& def) this->Defines.push_back(def); } -void cmIDEOptions::AddDefines(const char* defines) +void cmIDEOptions::AddDefines(std::string const& defines) { - if (defines) { + if (!defines.empty()) { // Expand the list of definitions. cmSystemTools::ExpandListArgument(defines, this->Defines); } @@ -179,9 +181,9 @@ void cmIDEOptions::AddInclude(const std::string& include) this->Includes.push_back(include); } -void cmIDEOptions::AddIncludes(const char* includes) +void cmIDEOptions::AddIncludes(std::string const& includes) { - if (includes) { + if (!includes.empty()) { // Expand the list of includes. cmSystemTools::ExpandListArgument(includes, this->Includes); } diff --git a/Source/cmIDEOptions.h b/Source/cmIDEOptions.h index 54cb524..a4e5757 100644 --- a/Source/cmIDEOptions.h +++ b/Source/cmIDEOptions.h @@ -22,12 +22,12 @@ public: // Store definitions, includes and flags. void AddDefine(const std::string& define); - void AddDefines(const char* defines); + void AddDefines(std::string const& defines); void AddDefines(const std::vector<std::string>& defines); std::vector<std::string> const& GetDefines() const; void AddInclude(const std::string& includes); - void AddIncludes(const char* includes); + void AddIncludes(std::string const& includes); void AddIncludes(const std::vector<std::string>& includes); std::vector<std::string> const& GetIncludes() const; @@ -95,11 +95,12 @@ protected: FlagTableCount = 16 }; cmIDEFlagTable const* FlagTable[FlagTableCount]; - void HandleFlag(const char* flag); - bool CheckFlagTable(cmIDEFlagTable const* table, const char* flag, + void HandleFlag(std::string const& flag); + bool CheckFlagTable(cmIDEFlagTable const* table, std::string const& flag, bool& flag_handled); - void FlagMapUpdate(cmIDEFlagTable const* entry, const char* new_value); - virtual void StoreUnknownFlag(const char* flag) = 0; + void FlagMapUpdate(cmIDEFlagTable const* entry, + std::string const& new_value); + virtual void StoreUnknownFlag(std::string const& flag) = 0; }; #endif diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 394f976..b5291a1 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -5,6 +5,7 @@ #include "cmsys/Glob.hxx" #include <sstream> #include <stddef.h> +#include <string.h> #include <utility> #include "cmAlgorithms.h" @@ -334,8 +335,8 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) // Check whether this is a DLL platform. bool dll_platform = - (this->Makefile->IsOn("WIN32") || this->Makefile->IsOn("CYGWIN") || - this->Makefile->IsOn("MINGW")); + strcmp(this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"), + "") != 0; for (std::string const& tgt : targetList.GetVector()) { @@ -360,17 +361,6 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) this->SetError(e.str()); return false; } - if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) { - std::string reason; - if (!this->Makefile->GetGlobalGenerator()->HasKnownObjectFileLocation( - &reason)) { - std::ostringstream e; - e << "TARGETS given OBJECT library \"" << tgt - << "\" which may not be installed" << reason << "."; - this->SetError(e.str()); - return false; - } - } // Store the target in the list to be installed. targets.push_back(target); } else { @@ -534,15 +524,23 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) case cmStateEnums::OBJECT_LIBRARY: { // Objects use OBJECT properties. if (!objectArgs.GetDestination().empty()) { + // Verify that we know where the objects are to install them. + std::string reason; + if (!this->Makefile->GetGlobalGenerator() + ->HasKnownObjectFileLocation(&reason)) { + std::ostringstream e; + e << "TARGETS given OBJECT library \"" << target.GetName() + << "\" whose objects may not be installed" << reason << "."; + this->SetError(e.str()); + return false; + } + objectGenerator = CreateInstallTargetGenerator(target, objectArgs, false); } else { - std::ostringstream e; - e << "TARGETS given no OBJECTS DESTINATION for object library " - "target \"" - << target.GetName() << "\"."; - this->SetError(e.str()); - return false; + // Installing an OBJECT library without a destination transforms + // it to an INTERFACE library. It installs no files but can be + // exported. } } break; case cmStateEnums::EXECUTABLE: { diff --git a/Source/cmLinkLineDeviceComputer.cxx b/Source/cmLinkLineDeviceComputer.cxx index 3beeae3..557fa41 100644 --- a/Source/cmLinkLineDeviceComputer.cxx +++ b/Source/cmLinkLineDeviceComputer.cxx @@ -3,9 +3,9 @@ #include "cmLinkLineDeviceComputer.h" -#include <set> #include <sstream> +#include "cmAlgorithms.h" #include "cmComputeLinkInformation.h" #include "cmGeneratorTarget.h" #include "cmGlobalNinjaGenerator.h" @@ -32,38 +32,32 @@ std::string cmLinkLineDeviceComputer::ComputeLinkLibraries( ItemVector const& items = cli.GetItems(); std::string config = cli.GetConfig(); for (auto const& item : items) { - if (!item.Target) { - continue; - } - - bool skippable = false; - switch (item.Target->GetType()) { - case cmStateEnums::SHARED_LIBRARY: - case cmStateEnums::MODULE_LIBRARY: - case cmStateEnums::INTERFACE_LIBRARY: - skippable = true; - break; - case cmStateEnums::STATIC_LIBRARY: - // If a static library is resolving its device linking, it should - // be removed for other device linking - skippable = - item.Target->GetPropertyAsBool("CUDA_RESOLVE_DEVICE_SYMBOLS"); - break; - default: - break; - } - - if (skippable) { - continue; - } - - std::set<std::string> langs; - item.Target->GetLanguages(langs, config); - if (langs.count("CUDA") == 0) { - continue; + if (item.Target) { + bool skip = false; + switch (item.Target->GetType()) { + case cmStateEnums::MODULE_LIBRARY: + case cmStateEnums::INTERFACE_LIBRARY: + skip = true; + break; + case cmStateEnums::STATIC_LIBRARY: + skip = item.Target->GetPropertyAsBool("CUDA_RESOLVE_DEVICE_SYMBOLS"); + break; + default: + break; + } + if (skip) { + continue; + } } if (item.IsPath) { + // nvcc understands absolute paths to libraries ending in '.a' should + // be passed to nvlink. Other extensions like '.so' or '.dylib' are + // rejected by the nvcc front-end even though nvlink knows to ignore + // them. Bypass the front-end via '-Xnvlink'. + if (!cmHasLiteralSuffix(item.Value, ".a")) { + fout << "-Xnvlink "; + } fout << this->ConvertToOutputFormat( this->ConvertToLinkReference(item.Value)); } else { diff --git a/Source/cmListCommand.cxx b/Source/cmListCommand.cxx index ae4f0a8..821e6d1 100644 --- a/Source/cmListCommand.cxx +++ b/Source/cmListCommand.cxx @@ -42,6 +42,9 @@ bool cmListCommand::InitialPass(std::vector<std::string> const& args, if (subCommand == "INSERT") { return this->HandleInsertCommand(args); } + if (subCommand == "JOIN") { + return this->HandleJoinCommand(args); + } if (subCommand == "REMOVE_AT") { return this->HandleRemoveAtCommand(args); } @@ -54,6 +57,9 @@ bool cmListCommand::InitialPass(std::vector<std::string> const& args, if (subCommand == "SORT") { return this->HandleSortCommand(args); } + if (subCommand == "SUBLIST") { + return this->HandleSublistCommand(args); + } if (subCommand == "REVERSE") { return this->HandleReverseCommand(args); } @@ -294,6 +300,34 @@ bool cmListCommand::HandleInsertCommand(std::vector<std::string> const& args) return true; } +bool cmListCommand::HandleJoinCommand(std::vector<std::string> const& args) +{ + if (args.size() != 4) { + std::ostringstream error; + error << "sub-command JOIN requires three arguments (" << args.size() - 1 + << " found)."; + this->SetError(error.str()); + return false; + } + + const std::string& listName = args[1]; + const std::string& glue = args[2]; + const std::string& variableName = args[3]; + + // expand the variable + std::vector<std::string> varArgsExpanded; + if (!this->GetList(varArgsExpanded, listName)) { + this->Makefile->AddDefinition(variableName, ""); + return true; + } + + std::string value = + cmJoin(cmMakeRange(varArgsExpanded.begin(), varArgsExpanded.end()), glue); + + this->Makefile->AddDefinition(variableName, value.c_str()); + return true; +} + bool cmListCommand::HandleRemoveItemCommand( std::vector<std::string> const& args) { @@ -396,6 +430,55 @@ bool cmListCommand::HandleSortCommand(std::vector<std::string> const& args) return true; } +bool cmListCommand::HandleSublistCommand(std::vector<std::string> const& args) +{ + if (args.size() != 5) { + std::ostringstream error; + error << "sub-command SUBLIST requires four arguments (" << args.size() - 1 + << " found)."; + this->SetError(error.str()); + return false; + } + + const std::string& listName = args[1]; + const std::string& variableName = args[args.size() - 1]; + + // expand the variable + std::vector<std::string> varArgsExpanded; + if (!this->GetList(varArgsExpanded, listName) || varArgsExpanded.empty()) { + this->Makefile->AddDefinition(variableName, ""); + return true; + } + + const int start = atoi(args[2].c_str()); + const int length = atoi(args[3].c_str()); + + using size_type = decltype(varArgsExpanded)::size_type; + + if (start < 0 || size_type(start) >= varArgsExpanded.size()) { + std::ostringstream error; + error << "begin index: " << start << " is out of range 0 - " + << varArgsExpanded.size() - 1; + this->SetError(error.str()); + return false; + } + if (length < -1) { + std::ostringstream error; + error << "length: " << length << " should be -1 or greater"; + this->SetError(error.str()); + return false; + } + + const size_type end = + (length == -1 || size_type(start + length) > varArgsExpanded.size()) + ? varArgsExpanded.size() + : size_type(start + length); + std::vector<std::string> sublist(varArgsExpanded.begin() + start, + varArgsExpanded.begin() + end); + this->Makefile->AddDefinition(variableName, cmJoin(sublist, ";").c_str()); + return true; +} + bool cmListCommand::HandleRemoveAtCommand(std::vector<std::string> const& args) { if (args.size() < 3) { diff --git a/Source/cmListCommand.h b/Source/cmListCommand.h index 2965399..d69d8f9 100644 --- a/Source/cmListCommand.h +++ b/Source/cmListCommand.h @@ -37,10 +37,12 @@ protected: bool HandleAppendCommand(std::vector<std::string> const& args); bool HandleFindCommand(std::vector<std::string> const& args); bool HandleInsertCommand(std::vector<std::string> const& args); + bool HandleJoinCommand(std::vector<std::string> const& args); bool HandleRemoveAtCommand(std::vector<std::string> const& args); bool HandleRemoveItemCommand(std::vector<std::string> const& args); bool HandleRemoveDuplicatesCommand(std::vector<std::string> const& args); bool HandleSortCommand(std::vector<std::string> const& args); + bool HandleSublistCommand(std::vector<std::string> const& args); bool HandleReverseCommand(std::vector<std::string> const& args); bool HandleFilterCommand(std::vector<std::string> const& args); bool FilterRegex(std::vector<std::string> const& args, bool includeMatches, diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index e942ff4..629d54a 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1561,6 +1561,7 @@ void cmLocalGenerator::AddCompilerRequirementFlag( static std::map<std::string, std::vector<std::string>> langStdMap; if (langStdMap.empty()) { // Maintain sorted order, most recent first. + langStdMap["CXX"].push_back("20"); langStdMap["CXX"].push_back("17"); langStdMap["CXX"].push_back("14"); langStdMap["CXX"].push_back("11"); diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 8c889fc..c1af92f 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -10,6 +10,7 @@ #include <stdio.h> #include <utility> +#include "cmCryptoHash.h" #include "cmCustomCommand.h" #include "cmCustomCommandGenerator.h" #include "cmGeneratedFileStream.h" @@ -24,6 +25,7 @@ #include "cmStateTypes.h" #include "cmSystemTools.h" #include "cmake.h" +#include "cmsys/FStream.hxx" cmLocalNinjaGenerator::cmLocalNinjaGenerator(cmGlobalGenerator* gg, cmMakefile* mf) @@ -286,8 +288,51 @@ void cmLocalNinjaGenerator::AppendCustomCommandDeps( } } +std::string cmLocalNinjaGenerator::WriteCommandScript( + std::vector<std::string> const& cmdLines, std::string const& customStep, + cmGeneratorTarget const* target) const +{ + std::string scriptPath; + if (target) { + scriptPath = target->GetSupportDirectory(); + } else { + scriptPath = this->GetCurrentBinaryDirectory(); + scriptPath += cmake::GetCMakeFilesDirectory(); + } + cmSystemTools::MakeDirectory(scriptPath); + scriptPath += '/'; + scriptPath += customStep; +#ifdef _WIN32 + scriptPath += ".bat"; +#else + scriptPath += ".sh"; +#endif + + cmsys::ofstream script(scriptPath.c_str()); + +#ifndef _WIN32 + script << "set -e\n\n"; +#endif + + for (auto const& i : cmdLines) { + std::string cmd = i; + // The command line was built assuming it would be written to + // the build.ninja file, so it uses '$$' for '$'. Remove this + // for the raw shell script. + cmSystemTools::ReplaceString(cmd, "$$", "$"); +#ifdef _WIN32 + script << cmd << " || exit /b" << '\n'; +#else + script << cmd << '\n'; +#endif + } + + return scriptPath; +} + std::string cmLocalNinjaGenerator::BuildCommandLine( - const std::vector<std::string>& cmdLines) + std::vector<std::string> const& cmdLines, std::string const& customStep, + cmGeneratorTarget const* target) const { // If we have no commands but we need to build a command anyway, use noop. // This happens when building a POST_BUILD value for link targets that @@ -296,6 +341,35 @@ std::string cmLocalNinjaGenerator::BuildCommandLine( return cmGlobalNinjaGenerator::SHELL_NOOP; } + // If this is a custom step then we will have no '$VAR' ninja placeholders. + // This means we can deal with long command sequences by writing to a script. + // Do this if the command lines are on the scale of the OS limit. + if (!customStep.empty()) { + size_t cmdLinesTotal = 0; + for (std::string const& cmd : cmdLines) { + cmdLinesTotal += cmd.length() + 6; + } + if (cmdLinesTotal > cmSystemTools::CalculateCommandLineLengthLimit() / 2) { + std::string const scriptPath = + this->WriteCommandScript(cmdLines, customStep, target); + std::string cmd +#ifndef _WIN32 + = "/bin/sh " +#endif + ; + cmd += this->ConvertToOutputFormat( + this->GetGlobalNinjaGenerator()->ConvertToNinjaPath(scriptPath), + cmOutputConverter::SHELL); + + // Add an unused argument based on script content so that Ninja + // knows when the command lines change. + cmd += " "; + cmCryptoHash hash(cmCryptoHash::AlgoSHA256); + cmd += hash.HashFile(scriptPath).substr(0, 16); + return cmd; + } + } + std::ostringstream cmd; for (std::vector<std::string>::const_iterator li = cmdLines.begin(); li != cmdLines.end(); ++li) @@ -406,10 +480,16 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement( "Phony custom command for " + ninjaOutputs[0], ninjaOutputs, ninjaDeps, cmNinjaDeps(), orderOnlyDeps, cmNinjaVars()); } else { + std::string customStep = cmSystemTools::GetFilenameName(ninjaOutputs[0]); + // Hash full path to make unique. + customStep += '-'; + cmCryptoHash hash(cmCryptoHash::AlgoSHA256); + customStep += hash.HashString(ninjaOutputs[0]).substr(0, 7); + this->GetGlobalNinjaGenerator()->WriteCustomCommandBuild( - this->BuildCommandLine(cmdLines), this->ConstructComment(ccg), - "Custom command for " + ninjaOutputs[0], cc->GetDepfile(), - cc->GetUsesTerminal(), + this->BuildCommandLine(cmdLines, customStep), + this->ConstructComment(ccg), "Custom command for " + ninjaOutputs[0], + cc->GetDepfile(), cc->GetUsesTerminal(), /*restat*/ !symbolic || !byproducts.empty(), ninjaOutputs, ninjaDeps, orderOnlyDeps); } diff --git a/Source/cmLocalNinjaGenerator.h b/Source/cmLocalNinjaGenerator.h index 95d8a61..f772fb0 100644 --- a/Source/cmLocalNinjaGenerator.h +++ b/Source/cmLocalNinjaGenerator.h @@ -59,7 +59,10 @@ public: return this->HomeRelativeOutputPath; } - std::string BuildCommandLine(const std::vector<std::string>& cmdLines); + std::string BuildCommandLine( + std::vector<std::string> const& cmdLines, + std::string const& customStep = std::string(), + cmGeneratorTarget const* target = nullptr) const; void AppendTargetOutputs(cmGeneratorTarget* target, cmNinjaDeps& outputs); void AppendTargetDepends( @@ -98,6 +101,10 @@ private: std::string MakeCustomLauncher(cmCustomCommandGenerator const& ccg); + std::string WriteCommandScript(std::vector<std::string> const& cmdLines, + std::string const& customStep, + cmGeneratorTarget const* target) const; + std::string HomeRelativeOutputPath; typedef std::map<cmCustomCommand const*, std::set<cmGeneratorTarget*>> diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index ddd8cc4..c9237a8 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -760,7 +760,8 @@ void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsBottom( // Write special "cmake_check_build_system" target to run cmake with // the --check-build-system flag. - { + if (!this->GlobalGenerator->GlobalSettingIsOn( + "CMAKE_SUPPRESS_REGENERATION")) { // Build command to run CMake to check if anything needs regenerating. std::string cmakefileName = cmake::GetCMakeFilesDirectoryPostSlash(); cmakefileName += "Makefile.cmake"; @@ -1580,7 +1581,11 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( std::string recursiveTarget = this->GetCurrentBinaryDirectory(); recursiveTarget += "/all"; - depends.push_back("cmake_check_build_system"); + bool regenerate = + !this->GlobalGenerator->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION"); + if (regenerate) { + depends.push_back("cmake_check_build_system"); + } std::string progressDir = this->GetBinaryDirectory(); progressDir += cmake::GetCMakeFilesDirectory(); @@ -1643,7 +1648,7 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( if (!noall || cmSystemTools::IsOff(noall)) { // Drive the build before installing. depends.push_back("all"); - } else { + } else if (regenerate) { // At least make sure the build system is up to date. depends.push_back("cmake_check_build_system"); } @@ -1657,24 +1662,26 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( this->WriteMakeRule(ruleFileStream, "Prepare targets for installation.", "preinstall/fast", depends, commands, true); - // write the depend rule, really a recompute depends rule - depends.clear(); - 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(std::move(runRule)); + if (regenerate) { + // write the depend rule, really a recompute depends rule + depends.clear(); + 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(std::move(runRule)); + } + this->CreateCDCommand(commands, this->GetBinaryDirectory(), + this->GetCurrentBinaryDirectory()); + this->WriteMakeRule(ruleFileStream, "clear depends", "depend", depends, + commands, true); } - this->CreateCDCommand(commands, this->GetBinaryDirectory(), - this->GetCurrentBinaryDirectory()); - this->WriteMakeRule(ruleFileStream, "clear depends", "depend", depends, - commands, true); } void cmLocalUnixMakefileGenerator3::ClearDependencies(cmMakefile* mf, diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 98b1c44..91ee09f 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -210,7 +210,8 @@ void cmLocalVisualStudio7Generator::CreateSingleVCProj( cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule() { - if (this->Makefile->IsOn("CMAKE_SUPPRESS_REGENERATION")) { + if (this->GlobalGenerator->GlobalSettingIsOn( + "CMAKE_SUPPRESS_REGENERATION")) { return nullptr; } @@ -791,10 +792,9 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( << "\\$(ConfigurationName)\"\n"; } targetOptions.OutputAdditionalIncludeDirectories( - fout, "\t\t\t\t", "\n", - this->FortranProject ? "Fortran" : langForClCompile); + fout, "\t\t\t\t", this->FortranProject ? "Fortran" : langForClCompile); targetOptions.OutputFlagMap(fout, "\t\t\t\t"); - targetOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t", "\n", + targetOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t", langForClCompile); fout << "\t\t\t\tObjectFile=\"$(IntDir)\\\"\n"; if (target->GetType() <= cmStateEnums::OBJECT_LIBRARY) { @@ -814,11 +814,10 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( "\t\t\t\tName=\"MASM\"\n" ; /* clang-format on */ - targetOptions.OutputAdditionalIncludeDirectories(fout, "\t\t\t\t", "\n", + targetOptions.OutputAdditionalIncludeDirectories(fout, "\t\t\t\t", "ASM_MASM"); // Use same preprocessor definitions as VCCLCompilerTool. - targetOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t", "\n", - "ASM_MASM"); + targetOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t", "ASM_MASM"); masmOptions.OutputFlagMap(fout, "\t\t\t\t"); /* clang-format off */ fout << @@ -836,18 +835,16 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( tool = "VFResourceCompilerTool"; } fout << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"\n"; - targetOptions.OutputAdditionalIncludeDirectories(fout, "\n\t\t\t\t", "", - "RC"); + targetOptions.OutputAdditionalIncludeDirectories(fout, "\t\t\t\t", "RC"); // add the -D flags to the RC tool - targetOptions.OutputPreprocessorDefinitions(fout, "\n\t\t\t\t", "", "RC"); - fout << "/>\n"; + targetOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t", "RC"); + fout << "\t\t\t/>\n"; tool = "VCMIDLTool"; if (this->FortranProject) { tool = "VFMIDLTool"; } fout << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"\n"; - targetOptions.OutputAdditionalIncludeDirectories(fout, "\n\t\t\t\t", "", - "MIDL"); + targetOptions.OutputAdditionalIncludeDirectories(fout, "\t\t\t\t", "MIDL"); fout << "\t\t\t\tMkTypLibCompatible=\"false\"\n"; if (gg->GetPlatformName() == "x64") { fout << "\t\t\t\tTargetEnvironment=\"3\"\n"; @@ -1677,17 +1674,17 @@ bool cmLocalVisualStudio7Generator::WriteGroup( } Options fileOptions(this, tool, table, gg->ExtraFlagTable); fileOptions.Parse(fc.CompileFlags.c_str()); - fileOptions.AddDefines(fc.CompileDefs.c_str()); - fileOptions.AddDefines(fc.CompileDefsConfig.c_str()); + fileOptions.AddDefines(fc.CompileDefs); + fileOptions.AddDefines(fc.CompileDefsConfig); // 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", + fout, "\t\t\t\t\t", ppLang == "CXX" && this->FortranProject ? "Fortran" : ppLang); - fileOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t\t", "\n", + fileOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t\t", ppLang); } if (!fc.AdditionalDeps.empty()) { @@ -2064,6 +2061,15 @@ std::string cmLocalVisualStudio7Generator::ConvertToXMLOutputPathSingle( return ret; } +void cmVS7GeneratorOptions::OutputFlag(std::ostream& fout, const char* indent, + const char* tag, + const std::string& content) +{ + fout << indent << tag << "=\""; + fout << cmLocalVisualStudio7GeneratorEscapeForXML(content); + fout << "\"\n"; +} + // This class is used to parse an existing vs 7 project // and extract the GUID class cmVS7XMLParser : public cmXMLParser diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h index 02e6931..22b4264 100644 --- a/Source/cmLocalVisualStudio7Generator.h +++ b/Source/cmLocalVisualStudio7Generator.h @@ -21,6 +21,19 @@ class cmMakefile; class cmSourceFile; class cmSourceGroup; +class cmVS7GeneratorOptions : public cmVisualStudioGeneratorOptions +{ +public: + cmVS7GeneratorOptions(cmLocalVisualStudioGenerator* lg, Tool tool, + cmVS7FlagTable const* table = nullptr, + cmVS7FlagTable const* extraTable = nullptr) + : cmVisualStudioGeneratorOptions(lg, tool, table, extraTable) + { + } + void OutputFlag(std::ostream& fout, const char* indent, const char* tag, + const std::string& content) override; +}; + /** \class cmLocalVisualStudio7Generator * \brief Write Visual Studio .NET project files. * @@ -70,7 +83,7 @@ protected: void CreateSingleVCProj(const std::string& lname, cmGeneratorTarget* tgt); private: - typedef cmVisualStudioGeneratorOptions Options; + typedef cmVS7GeneratorOptions Options; typedef cmLocalVisualStudio7GeneratorFCInfo FCInfo; std::string GetBuildTypeLinkerFlags(std::string rootLinkerFlags, const std::string& configName); diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index b468208..3ecd7eb 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -6,12 +6,12 @@ #include "cmsys/RegularExpression.hxx" #include <algorithm> #include <assert.h> +#include <cstring> #include <ctype.h> #include <iterator> #include <memory> // IWYU pragma: keep #include <sstream> #include <stdlib.h> -#include <string.h> #include <utility> #include "cmAlgorithms.h" @@ -158,6 +158,32 @@ bool cmMakefile::CheckCMP0037(std::string const& targetName, return true; } +void cmMakefile::MaybeWarnCMP0074(std::string const& pkg) +{ + // Warn if a <pkg>_ROOT variable we may use is set. + std::string const varName = pkg + "_ROOT"; + const char* var = this->GetDefinition(varName); + std::string env; + cmSystemTools::GetEnv(varName, env); + + bool const haveVar = var && *var; + bool const haveEnv = !env.empty(); + if ((haveVar || haveEnv) && this->WarnedCMP0074.insert(varName).second) { + std::ostringstream w; + w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0074) << "\n"; + if (haveVar) { + w << "CMake variable " << varName << " is set to:\n" + << " " << var << "\n"; + } + if (haveEnv) { + w << "Environment variable " << varName << " is set to:\n" + << " " << env << "\n"; + } + w << "For compatibility, CMake is ignoring the variable."; + this->IssueMessage(cmake::AUTHOR_WARNING, w.str()); + } +} + cmStringRange cmMakefile::GetIncludeDirectoriesEntries() const { return this->StateSnapshot.GetDirectory().GetIncludeDirectoriesEntries(); @@ -1464,7 +1490,7 @@ void cmMakefile::Configure() this->SetCheckCMP0000(true); // Implicitly set the version for the user. - this->SetPolicyVersion("2.4"); + this->SetPolicyVersion("2.4", std::string()); } } bool hasProject = false; @@ -1867,7 +1893,7 @@ cmTarget* cmMakefile::AddLibrary(const std::string& lname, // Clear its dependencies. Otherwise, dependencies might persist // over changes in CMakeLists.txt, making the information stale and // hence useless. - target->ClearDependencyInformation(*this, lname); + target->ClearDependencyInformation(*this); if (excludeFromAll) { target->SetProperty("EXCLUDE_FROM_ALL", "TRUE"); } @@ -3138,6 +3164,14 @@ void cmMakefile::SetArgcArgv(const std::vector<std::string>& args) cmSourceFile* cmMakefile::GetSource(const std::string& sourceName, cmSourceFileLocationKind kind) const { + // First check "Known" paths (avoids the creation of cmSourceFileLocation) + if (kind == cmSourceFileLocationKind::Known) { + auto sfsi = this->KnownFileSearchIndex.find(sourceName); + if (sfsi != this->KnownFileSearchIndex.end()) { + return sfsi->second; + } + } + cmSourceFileLocation sfl(this, sourceName, kind); auto name = this->GetCMakeInstance()->StripExtension(sfl.GetName()); #if defined(_WIN32) || defined(__APPLE__) @@ -3170,6 +3204,10 @@ cmSourceFile* cmMakefile::CreateSource(const std::string& sourceName, name = cmSystemTools::LowerCase(name); #endif this->SourceFileSearchIndex[name].push_back(sf); + // for "Known" paths add direct lookup (used for faster lookup in GetSource) + if (kind == cmSourceFileLocationKind::Known) { + this->KnownFileSearchIndex[sourceName] = sf; + } return sf; } @@ -3238,6 +3276,14 @@ int cmMakefile::TryCompile(const std::string& srcdir, // change to the tests directory and run cmake // use the cmake object instead of calling cmake cmWorkingDirectory workdir(bindir); + if (workdir.Failed()) { + this->IssueMessage(cmake::FATAL_ERROR, + "Failed to set working directory to " + bindir + " : " + + std::strerror(workdir.GetLastResult())); + cmSystemTools::SetFatalErrorOccured(); + this->IsSourceFileTryCompile = false; + return 1; + } // make sure the same generator is used // use this program as the cmake to be run, it should not @@ -3641,6 +3687,20 @@ void cmMakefile::AppendProperty(const std::string& prop, const char* value, const char* cmMakefile::GetProperty(const std::string& prop) const { + // Check for computed properties. + static std::string output; + if (prop == "TESTS") { + std::vector<std::string> keys; + // get list of keys + std::transform(this->Tests.begin(), this->Tests.end(), + std::back_inserter(keys), + [](decltype(this->Tests)::value_type const& pair) { + return pair.first; + }); + output = cmJoin(keys, ";"); + return output.c_str(); + } + return this->StateSnapshot.GetDirectory().GetProperty(prop); } @@ -4115,9 +4175,10 @@ void cmMakefile::PopSnapshot(bool reportError) assert(this->StateSnapshot.IsValid()); } -bool cmMakefile::SetPolicyVersion(const char* version) +bool cmMakefile::SetPolicyVersion(std::string const& version_min, + std::string const& version_max) { - return cmPolicies::ApplyPolicyVersion(this, version); + return cmPolicies::ApplyPolicyVersion(this, version_min, version_max); } bool cmMakefile::HasCMP0054AlreadyBeenReported( @@ -4162,7 +4223,7 @@ static const char* const CXX_FEATURES[] = { nullptr FOR_EACH_CXX_FEATURE( #undef FEATURE_STRING static const char* const C_STANDARDS[] = { "90", "99", "11" }; -static const char* const CXX_STANDARDS[] = { "98", "11", "14", "17" }; +static const char* const CXX_STANDARDS[] = { "98", "11", "14", "17", "20" }; bool cmMakefile::AddRequiredTargetFeature(cmTarget* target, const std::string& feature, @@ -4412,8 +4473,9 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, bool needCxx11 = false; bool needCxx14 = false; bool needCxx17 = false; + bool needCxx20 = false; this->CheckNeededCxxLanguage(feature, needCxx98, needCxx11, needCxx14, - needCxx17); + needCxx17, needCxx20); const char* existingCxxStandard = target->GetProperty("CXX_STANDARD"); if (!existingCxxStandard) { @@ -4433,7 +4495,8 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, /* clang-format off */ const char* const* needCxxLevel = - needCxx17 ? &CXX_STANDARDS[3] + needCxx20 ? &CXX_STANDARDS[4] + : needCxx17 ? &CXX_STANDARDS[3] : needCxx14 ? &CXX_STANDARDS[2] : needCxx11 ? &CXX_STANDARDS[1] : needCxx98 ? &CXX_STANDARDS[0] @@ -4445,7 +4508,8 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, void cmMakefile::CheckNeededCxxLanguage(const std::string& feature, bool& needCxx98, bool& needCxx11, - bool& needCxx14, bool& needCxx17) const + bool& needCxx14, bool& needCxx17, + bool& needCxx20) const { if (const char* propCxx98 = this->GetDefinition("CMAKE_CXX98_COMPILE_FEATURES")) { @@ -4471,6 +4535,12 @@ void cmMakefile::CheckNeededCxxLanguage(const std::string& feature, cmSystemTools::ExpandListArgument(propCxx17, props); needCxx17 = std::find(props.begin(), props.end(), feature) != props.end(); } + if (const char* propCxx20 = + this->GetDefinition("CMAKE_CXX20_COMPILE_FEATURES")) { + std::vector<std::string> props; + cmSystemTools::ExpandListArgument(propCxx20, props); + needCxx20 = std::find(props.begin(), props.end(), feature) != props.end(); + } } bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, @@ -4481,9 +4551,10 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, bool needCxx11 = false; bool needCxx14 = false; bool needCxx17 = false; + bool needCxx20 = false; this->CheckNeededCxxLanguage(feature, needCxx98, needCxx11, needCxx14, - needCxx17); + needCxx17, needCxx20); const char* existingCxxStandard = target->GetProperty("CXX_STANDARD"); const char* const* existingCxxLevel = nullptr; @@ -4528,7 +4599,8 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, /* clang-format off */ const char* const* needCxxLevel = - needCxx17 ? &CXX_STANDARDS[3] + needCxx20 ? &CXX_STANDARDS[4] + : needCxx17 ? &CXX_STANDARDS[3] : needCxx14 ? &CXX_STANDARDS[2] : needCxx11 ? &CXX_STANDARDS[1] : needCxx98 ? &CXX_STANDARDS[0] diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 5a30790..d2626cd 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -285,7 +285,8 @@ public: bool SetPolicy(cmPolicies::PolicyID id, cmPolicies::PolicyStatus status); bool SetPolicy(const char* id, cmPolicies::PolicyStatus status); cmPolicies::PolicyStatus GetPolicyStatus(cmPolicies::PolicyID id) const; - bool SetPolicyVersion(const char* version); + bool SetPolicyVersion(std::string const& version_min, + std::string const& version_max); void RecordPolicies(cmPolicies::PolicyMap& pm); //@} @@ -832,9 +833,11 @@ public: void RemoveExportBuildFileGeneratorCMP0024(cmExportBuildFileGenerator* gen); void AddExportBuildFileGenerator(cmExportBuildFileGenerator* gen); - // Maintain a stack of package names to determine the depth of find modules - // we are currently being called with - std::deque<std::string> FindPackageModuleStack; + // Maintain a stack of package roots to allow nested PACKAGE_ROOT_PATH + // searches + std::deque<std::vector<std::string>> FindPackageRootPathStack; + + void MaybeWarnCMP0074(std::string const& pkg); protected: // add link libraries and directories to the target @@ -861,6 +864,9 @@ protected: typedef std::unordered_map<std::string, SourceFileVec> SourceFileMap; SourceFileMap SourceFileSearchIndex; + // For "Known" paths we can store a direct filename to cmSourceFile map + std::unordered_map<std::string, cmSourceFile*> KnownFileSearchIndex; + // Tests std::map<std::string, cmTest*> Tests; @@ -985,7 +991,7 @@ private: bool& needC99, bool& needC11) const; void CheckNeededCxxLanguage(const std::string& feature, bool& needCxx98, bool& needCxx11, bool& needCxx14, - bool& needCxx17) const; + bool& needCxx17, bool& needCxx20) const; bool HaveCStandardAvailable(cmTarget const* target, const std::string& feature) const; @@ -998,6 +1004,7 @@ private: bool WarnUnused; bool CheckSystemVars; bool CheckCMP0000; + std::set<std::string> WarnedCMP0074; bool IsSourceFileTryCompile; mutable bool SuppressWatches; }; diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 73cf1f0..abe5ff3 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -643,6 +643,18 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( source.GetFullPath(), workingDirectory, compileCommand); } + // See if we need to use a compiler launcher like ccache or distcc + std::string compilerLauncher; + 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); + if (clauncher && *clauncher) { + compilerLauncher = clauncher; + } + } + // Maybe insert an include-what-you-use runner. if (!compileCommands.empty() && (lang == "C" || lang == "CXX")) { std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE"; @@ -656,6 +668,13 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( if ((iwyu && *iwyu) || (tidy && *tidy) || (cpplint && *cpplint) || (cppcheck && *cppcheck)) { std::string run_iwyu = "$(CMAKE_COMMAND) -E __run_co_compile"; + if (!compilerLauncher.empty()) { + // In __run_co_compile case the launcher command is supplied + // via --launcher=<maybe-list> and consumed + run_iwyu += " --launcher="; + run_iwyu += this->LocalGenerator->EscapeForShell(compilerLauncher); + compilerLauncher.clear(); + } if (iwyu && *iwyu) { run_iwyu += " --iwyu="; run_iwyu += this->LocalGenerator->EscapeForShell(iwyu); @@ -682,21 +701,15 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( } } - // Maybe insert a compiler launcher like ccache or distcc - 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); - if (clauncher && *clauncher) { - std::vector<std::string> launcher_cmd; - cmSystemTools::ExpandListArgument(clauncher, launcher_cmd, true); - for (std::string& i : launcher_cmd) { - i = this->LocalGenerator->EscapeForShell(i); - } - std::string const& run_launcher = cmJoin(launcher_cmd, " ") + " "; - compileCommands.front().insert(0, run_launcher); + // If compiler launcher was specified and not consumed above, it + // goes to the beginning of the command line. + if (!compileCommands.empty() && !compilerLauncher.empty()) { + std::vector<std::string> args; + cmSystemTools::ExpandListArgument(compilerLauncher, args, true); + for (std::string& i : args) { + i = this->LocalGenerator->EscapeForShell(i); } + compileCommands.front().insert(0, cmJoin(args, " ") + " "); } std::string launcher; diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index ddbc772..52e3677 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -187,7 +187,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule(bool useResponseFile) std::string responseFlag; if (!useResponseFile) { vars.Objects = "$in"; - vars.LinkLibraries = "$LINK_LIBRARIES"; + vars.LinkLibraries = "$LINK_PATH $LINK_LIBRARIES"; } else { std::string cmakeVarLang = "CMAKE_"; cmakeVarLang += this->TargetLinkLanguage; @@ -976,8 +976,10 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() preLinkCmdLines.push_back("cd " + homeOutDir); } - vars["PRE_LINK"] = localGen.BuildCommandLine(preLinkCmdLines); - std::string postBuildCmdLine = localGen.BuildCommandLine(postBuildCmdLines); + vars["PRE_LINK"] = localGen.BuildCommandLine(preLinkCmdLines, "pre-link", + this->GeneratorTarget); + std::string postBuildCmdLine = localGen.BuildCommandLine( + postBuildCmdLines, "post-build", this->GeneratorTarget); cmNinjaVars symlinkVars; bool const symlinkNeeded = diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index f4faf47..fa7d95a 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -653,6 +653,17 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) cmSystemTools::ExpandListArgument(compileCmd, compileCmds); } + // See if we need to use a compiler launcher like ccache or distcc + std::string compilerLauncher; + if (!compileCmds.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); + if (clauncher && *clauncher) { + compilerLauncher = clauncher; + } + } + // Maybe insert an include-what-you-use runner. if (!compileCmds.empty() && (lang == "C" || lang == "CXX")) { std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE"; @@ -668,6 +679,13 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) std::string run_iwyu = this->GetLocalGenerator()->ConvertToOutputFormat( cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL); run_iwyu += " -E __run_co_compile"; + if (!compilerLauncher.empty()) { + // In __run_co_compile case the launcher command is supplied + // via --launcher=<maybe-list> and consumed + run_iwyu += " --launcher="; + run_iwyu += this->LocalGenerator->EscapeForShell(compilerLauncher); + compilerLauncher.clear(); + } if (iwyu && *iwyu) { run_iwyu += " --iwyu="; run_iwyu += this->GetLocalGenerator()->EscapeForShell(iwyu); @@ -693,20 +711,15 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) } } - // Maybe insert a compiler launcher like ccache or distcc - if (!compileCmds.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); - if (clauncher && *clauncher) { - std::vector<std::string> launcher_cmd; - cmSystemTools::ExpandListArgument(clauncher, launcher_cmd, true); - for (std::string& i : launcher_cmd) { - i = this->LocalGenerator->EscapeForShell(i); - } - std::string const& run_launcher = cmJoin(launcher_cmd, " ") + " "; - compileCmds.front().insert(0, run_launcher); + // If compiler launcher was specified and not consumed above, it + // goes to the beginning of the command line. + if (!compileCmds.empty() && !compilerLauncher.empty()) { + std::vector<std::string> args; + cmSystemTools::ExpandListArgument(compilerLauncher, args, true); + for (std::string& i : args) { + i = this->LocalGenerator->EscapeForShell(i); } + compileCmds.front().insert(0, cmJoin(args, " ") + " "); } if (!compileCmds.empty()) { @@ -856,9 +869,27 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( vars["FLAGS"] = this->ComputeFlagsForObject(source, language); vars["DEFINES"] = this->ComputeDefines(source, language); vars["INCLUDES"] = this->ComputeIncludes(source, language); + if (!this->NeedDepTypeMSVC(language)) { - vars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat( - objectFileName + ".d", cmOutputConverter::SHELL); + bool replaceExt(false); + if (!language.empty()) { + std::string repVar = "CMAKE_"; + repVar += language; + repVar += "_DEPFILE_EXTENSION_REPLACE"; + replaceExt = this->Makefile->IsOn(repVar); + } + if (!replaceExt) { + // use original code + vars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat( + objectFileName + ".d", cmOutputConverter::SHELL); + } else { + // Replace the original source file extension with the + // depend file extension. + std::string dependFileName = + cmSystemTools::GetFilenameWithoutLastExtension(objectFileName) + ".d"; + vars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat( + objectFileDir + "/" + dependFileName, cmOutputConverter::SHELL); + } } this->ExportObjectCompileCommand( diff --git a/Source/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx index 7adeb8e..cc6d4b9 100644 --- a/Source/cmNinjaUtilityTargetGenerator.cxx +++ b/Source/cmNinjaUtilityTargetGenerator.cxx @@ -96,8 +96,8 @@ void cmNinjaUtilityTargetGenerator::Generate() this->GetBuildFileStream(), "Utility command for " + this->GetTargetName(), outputs, deps); } else { - std::string command = - this->GetLocalGenerator()->BuildCommandLine(commands); + std::string command = this->GetLocalGenerator()->BuildCommandLine( + commands, "utility", this->GeneratorTarget); const char* echoStr = this->GetGeneratorTarget()->GetProperty("EchoString"); std::string desc; diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index 25db929..fd42c53 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -6,7 +6,7 @@ #include <assert.h> #include <ctype.h> #include <set> -#include <sstream> +#include <string.h> #include <vector> #include "cmAlgorithms.h" @@ -341,12 +341,13 @@ redirection character (for example, ^>, ^<, or ^| ). If you need to use the caret character itself (^), use two in a row (^^). */ -int cmOutputConverter::Shell__CharIsWhitespace(char c) +/* Some helpers to identify character classes */ +static int Shell__CharIsWhitespace(char c) { return ((c == ' ') || (c == '\t')); } -int cmOutputConverter::Shell__CharNeedsQuotesOnUnix(char c) +static int Shell__CharNeedsQuotesOnUnix(char c) { return ((c == '\'') || (c == '`') || (c == ';') || (c == '#') || (c == '&') || (c == '$') || (c == '(') || (c == ')') || (c == '~') || @@ -354,12 +355,17 @@ int cmOutputConverter::Shell__CharNeedsQuotesOnUnix(char c) (c == '\\')); } -int cmOutputConverter::Shell__CharNeedsQuotesOnWindows(char c) +static int Shell__CharNeedsQuotesOnWindows(char c) { return ((c == '\'') || (c == '#') || (c == '&') || (c == '<') || (c == '>') || (c == '|') || (c == '^')); } +static int Shell__CharIsMakeVariableName(char c) +{ + return c && (c == '_' || isalpha((static_cast<int>(c)))); +} + int cmOutputConverter::Shell__CharNeedsQuotes(char c, int flags) { /* On Windows the built-in command shell echo never needs quotes. */ @@ -386,11 +392,6 @@ int cmOutputConverter::Shell__CharNeedsQuotes(char c, int flags) return 0; } -int cmOutputConverter::Shell__CharIsMakeVariableName(char c) -{ - return c && (c == '_' || isalpha((static_cast<int>(c)))); -} - const char* cmOutputConverter::Shell__SkipMakeVariables(const char* c) { while (*c == '$' && *(c + 1) == '(') { @@ -481,7 +482,9 @@ int cmOutputConverter::Shell__ArgumentNeedsQuotes(const char* in, int flags) std::string cmOutputConverter::Shell__GetArgument(const char* in, int flags) { - std::ostringstream out; + /* Output will be at least as long as input string. */ + std::string out; + out.reserve(strlen(in)); /* String iterator. */ const char* c; @@ -495,11 +498,11 @@ std::string cmOutputConverter::Shell__GetArgument(const char* in, int flags) /* Add the opening quote for this argument. */ if (flags & Shell_Flag_WatcomQuote) { if (flags & Shell_Flag_IsUnix) { - out << '"'; + out += '"'; } - out << '\''; + out += '\''; } else { - out << '"'; + out += '"'; } } @@ -511,7 +514,7 @@ std::string cmOutputConverter::Shell__GetArgument(const char* in, int flags) if (skip != c) { /* Copy to the end of the make variable references. */ while (c != skip) { - out << *c++; + out += *c++; } /* The make variable reference eliminates any escaping needed @@ -531,7 +534,7 @@ std::string cmOutputConverter::Shell__GetArgument(const char* in, int flags) quoted argument. */ if (*c == '\\' || *c == '"' || *c == '`' || *c == '$') { /* This character needs a backslash to escape it. */ - out << '\\'; + out += '\\'; } } else if (flags & Shell_Flag_EchoWindows) { /* On Windows the built-in command shell echo never needs escaping. */ @@ -545,11 +548,11 @@ std::string cmOutputConverter::Shell__GetArgument(const char* in, int flags) backslashes. */ while (windows_backslashes > 0) { --windows_backslashes; - out << '\\'; + out += '\\'; } /* Add the backslash to escape the double-quote. */ - out << '\\'; + out += '\\'; } else { /* We encountered a normal character. This eliminates any escaping needed for preceding backslashes. */ @@ -562,7 +565,7 @@ std::string cmOutputConverter::Shell__GetArgument(const char* in, int flags) if (flags & Shell_Flag_Make) { /* In Makefiles a dollar is written $$. The make tool will replace it with just $ before passing it to the shell. */ - out << "$$"; + out += "$$"; } else if (flags & Shell_Flag_VSIDE) { /* In a VS IDE a dollar is written "$". If this is written in an un-quoted argument it starts a quoted segment, inserts @@ -570,30 +573,30 @@ std::string cmOutputConverter::Shell__GetArgument(const char* in, int flags) argument it ends quoting, inserts the $ and restarts quoting. Either way the $ is isolated from surrounding text to avoid looking like a variable reference. */ - out << "\"$\""; + out += "\"$\""; } else { /* Otherwise a dollar is written just $. */ - out << '$'; + out += '$'; } } else if (*c == '#') { if ((flags & Shell_Flag_Make) && (flags & Shell_Flag_WatcomWMake)) { /* In Watcom WMake makefiles a pound is written $#. The make tool will replace it with just # before passing it to the shell. */ - out << "$#"; + out += "$#"; } else { /* Otherwise a pound is written just #. */ - out << '#'; + out += '#'; } } else if (*c == '%') { if ((flags & Shell_Flag_VSIDE) || ((flags & Shell_Flag_Make) && ((flags & Shell_Flag_MinGWMake) || (flags & Shell_Flag_NMake)))) { /* In the VS IDE, NMake, or MinGW make a percent is written %%. */ - out << "%%"; + out += "%%"; } else { /* Otherwise a percent is written just %. */ - out << '%'; + out += '%'; } } else if (*c == ';') { if (flags & Shell_Flag_VSIDE) { @@ -602,14 +605,14 @@ std::string cmOutputConverter::Shell__GetArgument(const char* in, int flags) inserts the ; and ends the segment. If it is written in a quoted argument it ends quoting, inserts the ; and restarts quoting. Either way the ; is isolated. */ - out << "\";\""; + out += "\";\""; } else { /* Otherwise a semicolon is written just ;. */ - out << ';'; + out += ';'; } } else { /* Store this character. */ - out << *c; + out += *c; } } @@ -617,19 +620,19 @@ std::string cmOutputConverter::Shell__GetArgument(const char* in, int flags) /* Add enough backslashes to escape any trailing ones. */ while (windows_backslashes > 0) { --windows_backslashes; - out << '\\'; + out += '\\'; } /* Add the closing quote for this argument. */ if (flags & Shell_Flag_WatcomQuote) { - out << '\''; + out += '\''; if (flags & Shell_Flag_IsUnix) { - out << '"'; + out += '"'; } } else { - out << '"'; + out += '"'; } } - return out.str(); + return out; } diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index ae15055..ed7143c 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -117,11 +117,7 @@ public: private: cmState* GetState() const; - static int Shell__CharIsWhitespace(char c); - static int Shell__CharNeedsQuotesOnUnix(char c); - static int Shell__CharNeedsQuotesOnWindows(char c); static int Shell__CharNeedsQuotes(char c, int flags); - static int Shell__CharIsMakeVariableName(char c); static const char* Shell__SkipMakeVariables(const char* c); static int Shell__ArgumentNeedsQuotes(const char* in, int flags); static std::string Shell__GetArgument(const char* in, int flags); diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx index e7d1b72..dba22b3 100644 --- a/Source/cmPolicies.cxx +++ b/Source/cmPolicies.cxx @@ -153,31 +153,26 @@ static bool GetPolicyDefault(cmMakefile* mf, std::string const& policy, return true; } -bool cmPolicies::ApplyPolicyVersion(cmMakefile* mf, const char* version) +bool cmPolicies::ApplyPolicyVersion(cmMakefile* mf, + std::string const& version_min, + std::string const& version_max) { - std::string ver = "2.4.0"; - - if (version && strlen(version) > 0) { - ver = version; - } - - unsigned int majorVer = 2; - unsigned int minorVer = 0; - unsigned int patchVer = 0; - unsigned int tweakVer = 0; - - // parse the string - if (sscanf(ver.c_str(), "%u.%u.%u.%u", &majorVer, &minorVer, &patchVer, - &tweakVer) < 2) { + // Parse components of the minimum version. + unsigned int minMajor = 2; + unsigned int minMinor = 0; + unsigned int minPatch = 0; + unsigned int minTweak = 0; + if (sscanf(version_min.c_str(), "%u.%u.%u.%u", &minMajor, &minMinor, + &minPatch, &minTweak) < 2) { std::ostringstream e; - e << "Invalid policy version value \"" << ver << "\". " + e << "Invalid policy version value \"" << version_min << "\". " << "A numeric major.minor[.patch[.tweak]] must be given."; mf->IssueMessage(cmake::FATAL_ERROR, e.str()); return false; } // it is an error if the policy version is less than 2.4 - if (majorVer < 2 || (majorVer == 2 && minorVer < 4)) { + if (minMajor < 2 || (minMajor == 2 && minMinor < 4)) { mf->IssueMessage( cmake::FATAL_ERROR, "Compatibility with CMake < 2.4 is not supported by CMake >= 3.0. " @@ -188,19 +183,19 @@ bool cmPolicies::ApplyPolicyVersion(cmMakefile* mf, const char* version) // It is an error if the policy version is greater than the running // CMake. - if (majorVer > cmVersion::GetMajorVersion() || - (majorVer == cmVersion::GetMajorVersion() && - minorVer > cmVersion::GetMinorVersion()) || - (majorVer == cmVersion::GetMajorVersion() && - minorVer == cmVersion::GetMinorVersion() && - patchVer > cmVersion::GetPatchVersion()) || - (majorVer == cmVersion::GetMajorVersion() && - minorVer == cmVersion::GetMinorVersion() && - patchVer == cmVersion::GetPatchVersion() && - tweakVer > cmVersion::GetTweakVersion())) { + if (minMajor > cmVersion::GetMajorVersion() || + (minMajor == cmVersion::GetMajorVersion() && + minMinor > cmVersion::GetMinorVersion()) || + (minMajor == cmVersion::GetMajorVersion() && + minMinor == cmVersion::GetMinorVersion() && + minPatch > cmVersion::GetPatchVersion()) || + (minMajor == cmVersion::GetMajorVersion() && + minMinor == cmVersion::GetMinorVersion() && + minPatch == cmVersion::GetPatchVersion() && + minTweak > cmVersion::GetTweakVersion())) { std::ostringstream e; e << "An attempt was made to set the policy version of CMake to \"" - << version << "\" which is greater than this version of CMake. " + << version_min << "\" which is greater than this version of CMake. " << "This is not allowed because the greater version may have new " << "policies not known to this CMake. " << "You may need a newer CMake version to build this project."; @@ -208,6 +203,52 @@ bool cmPolicies::ApplyPolicyVersion(cmMakefile* mf, const char* version) return false; } + unsigned int polMajor = minMajor; + unsigned int polMinor = minMinor; + unsigned int polPatch = minPatch; + + if (!version_max.empty()) { + // Parse components of the maximum version. + unsigned int maxMajor = 0; + unsigned int maxMinor = 0; + unsigned int maxPatch = 0; + unsigned int maxTweak = 0; + if (sscanf(version_max.c_str(), "%u.%u.%u.%u", &maxMajor, &maxMinor, + &maxPatch, &maxTweak) < 2) { + std::ostringstream e; + e << "Invalid policy max version value \"" << version_max << "\". " + << "A numeric major.minor[.patch[.tweak]] must be given."; + mf->IssueMessage(cmake::FATAL_ERROR, e.str()); + return false; + } + + // It is an error if the min version is greater than the max version. + if (minMajor > maxMajor || (minMajor == maxMajor && minMinor > maxMinor) || + (minMajor == maxMajor && minMinor == maxMinor && + minPatch > maxPatch) || + (minMajor == maxMajor && minMinor == maxMinor && + minPatch == maxPatch && minTweak > maxTweak)) { + std::ostringstream e; + e << "Policy VERSION range \"" << version_min << "..." << version_max + << "\"" + << " specifies a larger minimum than maximum."; + mf->IssueMessage(cmake::FATAL_ERROR, e.str()); + return false; + } + + // Use the max version as the policy version. + polMajor = maxMajor; + polMinor = maxMinor; + polPatch = maxPatch; + } + + return cmPolicies::ApplyPolicyVersion(mf, polMajor, polMinor, polPatch); +} + +bool cmPolicies::ApplyPolicyVersion(cmMakefile* mf, unsigned int majorVer, + unsigned int minorVer, + unsigned int patchVer) +{ // now loop over all the policies and set them as appropriate std::vector<cmPolicies::PolicyID> ancientPolicies; for (PolicyID pid = cmPolicies::CMP0000; pid != cmPolicies::CMPCOUNT; diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index c39f927..a21c778 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -214,7 +214,12 @@ class cmMakefile; 3, 10, 0, cmPolicies::WARN) \ SELECT(POLICY, CMP0072, \ "FindOpenGL prefers GLVND by default when available.", 3, 11, 0, \ - cmPolicies::WARN) + cmPolicies::WARN) \ + SELECT(POLICY, CMP0073, \ + "Do not produce legacy _LIB_DEPENDS cache entries.", 3, 12, 0, \ + cmPolicies::WARN) \ + SELECT(POLICY, CMP0074, "find_package uses PackageName_ROOT variables.", 3, \ + 12, 0, cmPolicies::WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) #define CM_FOR_EACH_POLICY_ID(POLICY) \ @@ -238,7 +243,8 @@ class cmMakefile; F(CMP0063) \ F(CMP0065) \ F(CMP0068) \ - F(CMP0069) + F(CMP0069) \ + F(CMP0073) /** \class cmPolicies * \brief Handles changes in CMake behavior and policies @@ -284,7 +290,11 @@ public: static cmPolicies::PolicyStatus GetPolicyStatus(cmPolicies::PolicyID id); ///! Set a policy level for this listfile - static bool ApplyPolicyVersion(cmMakefile* mf, const char* version); + static bool ApplyPolicyVersion(cmMakefile* mf, + std::string const& version_min, + std::string const& version_max); + static bool ApplyPolicyVersion(cmMakefile* mf, unsigned int majorVer, + unsigned int minorVer, unsigned int patchVer); ///! return a warning string for a given policy static std::string GetPolicyWarning(cmPolicies::PolicyID id); diff --git a/Source/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx index dfa1858..6ddb0b8 100644 --- a/Source/cmProjectCommand.cxx +++ b/Source/cmProjectCommand.cxx @@ -3,9 +3,11 @@ #include "cmProjectCommand.h" #include "cmsys/RegularExpression.hxx" +#include <functional> #include <sstream> #include <stdio.h> +#include "cmAlgorithms.h" #include "cmMakefile.h" #include "cmPolicies.h" #include "cmStateTypes.h" @@ -66,12 +68,19 @@ bool cmProjectCommand::InitialPass(std::vector<std::string> const& args, bool haveVersion = false; bool haveLanguages = false; bool haveDescription = false; + bool haveHomepage = false; std::string version; std::string description; + std::string homepage; std::vector<std::string> languages; + std::function<void()> missedValueReporter; + auto resetReporter = [&missedValueReporter]() { + missedValueReporter = std::function<void()>(); + }; enum Doing { DoingDescription, + DoingHomepage, DoingLanguages, DoingVersion }; @@ -85,7 +94,18 @@ bool cmProjectCommand::InitialPass(std::vector<std::string> const& args, return true; } haveLanguages = true; + if (missedValueReporter) { + missedValueReporter(); + } doing = DoingLanguages; + if (!languages.empty()) { + std::string msg = + "the following parameters must be specified after LANGUAGES " + "keyword: "; + msg += cmJoin(languages, ", "); + msg += '.'; + this->Makefile->IssueMessage(cmake::WARNING, msg); + } } else if (args[i] == "VERSION") { if (haveVersion) { this->Makefile->IssueMessage(cmake::FATAL_ERROR, @@ -94,7 +114,17 @@ bool cmProjectCommand::InitialPass(std::vector<std::string> const& args, return true; } haveVersion = true; + if (missedValueReporter) { + missedValueReporter(); + } doing = DoingVersion; + missedValueReporter = [this, &resetReporter]() { + this->Makefile->IssueMessage( + cmake::WARNING, + "VERSION keyword not followed by a value or was followed by a " + "value that expanded to nothing."); + resetReporter(); + }; } else if (args[i] == "DESCRIPTION") { if (haveDescription) { this->Makefile->IssueMessage( @@ -103,23 +133,61 @@ bool cmProjectCommand::InitialPass(std::vector<std::string> const& args, return true; } haveDescription = true; + if (missedValueReporter) { + missedValueReporter(); + } doing = DoingDescription; + missedValueReporter = [this, &resetReporter]() { + this->Makefile->IssueMessage( + cmake::WARNING, + "DESCRIPTION keyword not followed by a value or was followed " + "by a value that expanded to nothing."); + resetReporter(); + }; + } else if (args[i] == "HOMEPAGE_URL") { + if (haveHomepage) { + this->Makefile->IssueMessage( + cmake::FATAL_ERROR, "HOMEPAGE_URL may be specified at most once."); + cmSystemTools::SetFatalErrorOccured(); + return true; + } + haveHomepage = true; + doing = DoingHomepage; + missedValueReporter = [this, &resetReporter]() { + this->Makefile->IssueMessage( + cmake::WARNING, + "HOMEPAGE_URL keyword not followed by a value or was followed " + "by a value that expanded to nothing."); + resetReporter(); + }; } else if (doing == DoingVersion) { doing = DoingLanguages; version = args[i]; + resetReporter(); } else if (doing == DoingDescription) { doing = DoingLanguages; description = args[i]; + resetReporter(); + } else if (doing == DoingHomepage) { + doing = DoingLanguages; + homepage = args[i]; + resetReporter(); } else // doing == DoingLanguages { languages.push_back(args[i]); } } - if (haveVersion && !haveLanguages && !languages.empty()) { + if (missedValueReporter) { + missedValueReporter(); + } + + if ((haveVersion || haveDescription || haveHomepage) && !haveLanguages && + !languages.empty()) { this->Makefile->IssueMessage( cmake::FATAL_ERROR, - "project with VERSION must use LANGUAGES before language names."); + "project with VERSION, DESCRIPTION or HOMEPAGE_URL must " + "use LANGUAGES before language names."); cmSystemTools::SetFatalErrorOccured(); return true; } @@ -216,6 +284,8 @@ bool cmProjectCommand::InitialPass(std::vector<std::string> const& args, if (haveDescription) { this->Makefile->AddDefinition("PROJECT_DESCRIPTION", description.c_str()); + this->Makefile->AddDefinition(projectName + "_DESCRIPTION", + description.c_str()); // Set the CMAKE_PROJECT_DESCRIPTION variable to be the highest-level // project name in the tree. If there are two project commands // in the same CMakeLists.txt file, and it is the top level @@ -230,6 +300,24 @@ bool cmProjectCommand::InitialPass(std::vector<std::string> const& args, } } + if (haveHomepage) { + this->Makefile->AddDefinition("PROJECT_HOMEPAGE_URL", homepage.c_str()); + this->Makefile->AddDefinition(projectName + "_HOMEPAGE_URL", + homepage.c_str()); + // Set the CMAKE_PROJECT_HOMEPAGE_URL variable to be the highest-level + // project name in the tree. If there are two project commands + // in the same CMakeLists.txt file, and it is the top level + // CMakeLists.txt file, then go with the last one. + if (!this->Makefile->GetDefinition("CMAKE_PROJECT_HOMEPAGE_URL") || + (this->Makefile->IsRootMakefile())) { + this->Makefile->AddDefinition("CMAKE_PROJECT_HOMEPAGE_URL", + homepage.c_str()); + this->Makefile->AddCacheDefinition( + "CMAKE_PROJECT_HOMEPAGE_URL", homepage.c_str(), + "Value Computed by CMake", cmStateEnums::STATIC); + } + } + if (languages.empty()) { // if no language is specified do c and c++ languages.push_back("C"); diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx index 4aa1b1f..bf184d8 100644 --- a/Source/cmQtAutoGenerator.cxx +++ b/Source/cmQtAutoGenerator.cxx @@ -681,7 +681,7 @@ bool cmQtAutoGenerator::Run(std::string const& infoFile, 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"); + makefile->SetPolicyVersion("3.9", std::string()); gg.SetCurrentMakefile(makefile.get()); success = this->Init(makefile.get()); } diff --git a/Source/cmQtAutoGeneratorMocUic.cxx b/Source/cmQtAutoGeneratorMocUic.cxx index e2fd158..b1be967 100644 --- a/Source/cmQtAutoGeneratorMocUic.cxx +++ b/Source/cmQtAutoGeneratorMocUic.cxx @@ -434,7 +434,7 @@ bool cmQtAutoGeneratorMocUic::JobParseT::ParseMocSource(WorkerT& wrk, JobHandleT jobHandle(new JobMocT(std::move(jobPre.SourceFile), FileName, std::move(jobPre.IncludeString))); if (jobPre.self) { - // Read depdendencies from this source + // Read dependencies from this source static_cast<JobMocT&>(*jobHandle).FindDependencies(wrk, meta.Content); } if (!wrk.Gen().ParallelJobPushMoc(jobHandle)) { @@ -452,7 +452,7 @@ bool cmQtAutoGeneratorMocUic::JobParseT::ParseMocHeader(WorkerT& wrk, if (!macroName.empty()) { JobHandleT jobHandle( new JobMocT(std::string(FileName), std::string(), std::string())); - // Read depdendencies from this source + // Read dependencies from this source static_cast<JobMocT&>(*jobHandle).FindDependencies(wrk, meta.Content); success = wrk.Gen().ParallelJobPushMoc(jobHandle); } @@ -1381,7 +1381,7 @@ bool cmQtAutoGeneratorMocUic::Init(cmMakefile* makefile) // Compare list sizes if (sources.size() != options.size()) { std::ostringstream ost; - ost << "files/options lists sizes missmatch (" << sources.size() << "/" + ost << "files/options lists sizes mismatch (" << sources.size() << "/" << options.size() << ")"; Log().ErrorFile(GeneratorT::UIC, InfoFile(), ost.str()); return false; diff --git a/Source/cmRulePlaceholderExpander.h b/Source/cmRulePlaceholderExpander.h index 7b19210..a7d8cee 100644 --- a/Source/cmRulePlaceholderExpander.h +++ b/Source/cmRulePlaceholderExpander.h @@ -24,7 +24,7 @@ public: this->TargetImpLib = targetImpLib; } - // Create a struct to hold the varibles passed into + // Create a struct to hold the variables passed into // ExpandRuleVariables struct RuleVariables { diff --git a/Source/cmSearchPath.h b/Source/cmSearchPath.h index fd0c7c5..2a576ed 100644 --- a/Source/cmSearchPath.h +++ b/Source/cmSearchPath.h @@ -39,10 +39,10 @@ public: void AddCMakePrefixPath(const std::string& variable); void AddEnvPrefixPath(const std::string& variable, bool stripBin = false); void AddSuffixes(const std::vector<std::string>& suffixes); - -protected: void AddPrefixPaths(const std::vector<std::string>& paths, const char* base = nullptr); + +protected: void AddPathInternal(const std::string& path, const char* base = nullptr); cmFindCommon* FC; diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx index 55af078..9631912 100644 --- a/Source/cmStringCommand.cxx +++ b/Source/cmStringCommand.cxx @@ -68,6 +68,9 @@ bool cmStringCommand::InitialPass(std::vector<std::string> const& args, if (subCommand == "CONCAT") { return this->HandleConcatCommand(args); } + if (subCommand == "JOIN") { + return this->HandleJoinCommand(args); + } if (subCommand == "SUBSTRING") { return this->HandleSubstringCommand(args); } @@ -677,8 +680,26 @@ bool cmStringCommand::HandleConcatCommand(std::vector<std::string> const& args) return false; } - std::string const& variableName = args[1]; - std::string value = cmJoin(cmMakeRange(args).advance(2), std::string()); + return this->joinImpl(args, std::string(), 1); +} + +bool cmStringCommand::HandleJoinCommand(std::vector<std::string> const& args) +{ + if (args.size() < 3) { + this->SetError("sub-command JOIN requires at least two arguments."); + return false; + } + + return this->joinImpl(args, args[1], 2); +} + +bool cmStringCommand::joinImpl(std::vector<std::string> const& args, + std::string const& glue, const size_t varIdx) +{ + std::string const& variableName = args[varIdx]; + // NOTE Items to concat/join placed right after the variable for + // both `CONCAT` and `JOIN` sub-commands. + std::string value = cmJoin(cmMakeRange(args).advance(varIdx + 1), glue); this->Makefile->AddDefinition(variableName, value.c_str()); return true; diff --git a/Source/cmStringCommand.h b/Source/cmStringCommand.h index b287e37..569ed83 100644 --- a/Source/cmStringCommand.h +++ b/Source/cmStringCommand.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <cstddef> #include <string> #include <vector> @@ -48,6 +49,7 @@ protected: bool HandleAppendCommand(std::vector<std::string> const& args); bool HandlePrependCommand(std::vector<std::string> const& args); bool HandleConcatCommand(std::vector<std::string> const& args); + bool HandleJoinCommand(std::vector<std::string> const& args); bool HandleStripCommand(std::vector<std::string> const& args); bool HandleRandomCommand(std::vector<std::string> const& args); bool HandleFindCommand(std::vector<std::string> const& args); @@ -56,6 +58,9 @@ protected: bool HandleGenexStripCommand(std::vector<std::string> const& args); bool HandleUuidCommand(std::vector<std::string> const& args); + bool joinImpl(std::vector<std::string> const& args, std::string const& glue, + size_t varIdx); + class RegexReplacement { public: diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index eeb73c3..94c5ee8 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -1509,7 +1509,7 @@ cmSystemTools::SaveRestoreEnvironment::~SaveRestoreEnvironment() void cmSystemTools::EnableVSConsoleOutput() { #ifdef _WIN32 - // Visual Studio 8 2005 (devenv.exe or VCExpress.exe) will not + // Visual Studio tools like devenv may not // display output to the console unless this environment variable is // set. We need it to capture the output of these build tools. // Note for future work that one could pass "/out \\.\pipe\NAME" to diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index cd11c4b..d17a85a 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -114,15 +114,12 @@ const char* cmTargetPropertyComputer::GetSources<cmTarget>( } if (!noMessage) { e << "Target \"" << tgt->GetName() - << "\" contains " - "$<TARGET_OBJECTS> generator expression in its sources " - "list. " - "This content was not previously part of the SOURCES " - "property " - "when that property was read at configure time. Code " - "reading " - "that property needs to be adapted to ignore the generator " - "expression using the string(GENEX_STRIP) command."; + << "\" contains $<TARGET_OBJECTS> generator expression in its " + "sources list. This content was not previously part of the " + "SOURCES property when that property was read at configure " + "time. Code reading that property needs to be adapted to " + "ignore the generator expression using the string(GENEX_STRIP) " + "command."; messenger->IssueMessage(messageType, e.str(), context); } if (addContent) { @@ -189,18 +186,10 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, this->ImportedGloballyVisible = vis == VisibilityImportedGlobally; this->BuildInterfaceIncludesAppended = false; - // only add dependency information for library targets - if (this->TargetTypeValue >= cmStateEnums::STATIC_LIBRARY && - this->TargetTypeValue <= cmStateEnums::MODULE_LIBRARY) { - this->RecordDependencies = true; - } else { - this->RecordDependencies = false; - } - // Check whether this is a DLL platform. this->DLLPlatform = - (this->Makefile->IsOn("WIN32") || this->Makefile->IsOn("CYGWIN") || - this->Makefile->IsOn("MINGW")); + strcmp(this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"), + "") != 0; // Check whether we are targeting an Android platform. this->IsAndroid = @@ -286,6 +275,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, this->SetPropertyDefault("CUDA_SEPARABLE_COMPILATION", nullptr); this->SetPropertyDefault("LINK_SEARCH_START_STATIC", nullptr); this->SetPropertyDefault("LINK_SEARCH_END_STATIC", nullptr); + this->SetPropertyDefault("FOLDER", nullptr); } // Collect the set of configuration types. @@ -509,7 +499,7 @@ std::string cmTarget::ProcessSourceItemCMP0049(const std::string& s) { std::string src = s; - // For backwards compatibility replace varibles in source names. + // For backwards compatibility replace variables in source names. // This should eventually be removed. this->Makefile->ExpandVariablesInString(src); if (src != s) { @@ -638,27 +628,11 @@ const std::vector<std::string>& cmTarget::GetLinkDirectories() const return this->LinkDirectories; } -void cmTarget::ClearDependencyInformation(cmMakefile& mf, - const std::string& target) +void cmTarget::ClearDependencyInformation(cmMakefile& mf) { - // Clear the dependencies. The cache variable must exist iff we are - // recording dependency information for this target. - std::string depname = target; + std::string depname = this->GetName(); depname += "_LIB_DEPENDS"; - if (this->RecordDependencies) { - mf.AddCacheDefinition(depname, "", "Dependencies for target", - cmStateEnums::STATIC); - } else { - if (mf.GetDefinition(depname)) { - std::string message = "Target "; - message += target; - message += " has dependency information when it shouldn't.\n"; - message += "Your cache is probably stale. Please remove the entry\n "; - message += depname; - message += "\nfrom the cache."; - cmSystemTools::Error(message.c_str()); - } - } + mf.RemoveCacheDefinition(depname); } std::string cmTarget::GetDebugGeneratorExpressions( @@ -742,19 +716,15 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, const std::string& lib, } if (cmGeneratorExpression::Find(lib) != std::string::npos || - (tgt && tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) || + (tgt && (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY || + tgt->GetType() == cmStateEnums::OBJECT_LIBRARY)) || (this->Name == lib)) { return; } - { - cmTarget::LibraryID tmp; - tmp.first = lib; - tmp.second = llt; - this->OriginalLinkLibraries.emplace_back(lib, llt); - } + this->OriginalLinkLibraries.emplace_back(lib, llt); - // Add the explicit dependency information for this target. This is + // Add the explicit dependency information for libraries. This is // simply a set of libraries separated by ";". There should always // be a trailing ";". These library names are not canonical, in that // they may be "-framework x", "-ly", "/path/libz.a", etc. @@ -762,7 +732,10 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, const std::string& lib, // may be purposefully duplicated to handle recursive dependencies, // and we removing one instance will break the link line. Duplicates // will be appropriately eliminated at emit time. - if (this->RecordDependencies) { + if (this->TargetTypeValue >= cmStateEnums::STATIC_LIBRARY && + this->TargetTypeValue <= cmStateEnums::MODULE_LIBRARY && + (this->GetPolicyStatusCMP0073() == cmPolicies::OLD || + this->GetPolicyStatusCMP0073() == cmPolicies::WARN)) { std::string targetEntry = this->Name; targetEntry += "_LIB_DEPENDS"; std::string dependencies; diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 56f3e3a..62c4e22 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -137,7 +137,7 @@ public: /** * Clear the dependency information recorded for this target, if any. */ - void ClearDependencyInformation(cmMakefile& mf, const std::string& target); + void ClearDependencyInformation(cmMakefile& mf); void AddLinkLibrary(cmMakefile& mf, const std::string& lib, cmTargetLinkLibraryType llt); @@ -310,7 +310,6 @@ private: cmTargetInternalPointer Internal; cmStateEnums::TargetType TargetTypeValue; bool HaveInstallRule; - bool RecordDependencies; bool DLLPlatform; bool IsAndroid; bool IsImportedTarget; diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx index 9e4575a..699fff8 100644 --- a/Source/cmTargetLinkLibrariesCommand.cxx +++ b/Source/cmTargetLinkLibrariesCommand.cxx @@ -94,16 +94,6 @@ 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] << "\" " - << "may not link to anything."; - this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); - cmSystemTools::SetFatalErrorOccured(); - return true; - } - // Having a UTILITY library on the LHS is a bug. if (this->Target->GetType() == cmStateEnums::UTILITY) { std::ostringstream e; @@ -401,14 +391,15 @@ bool cmTargetLinkLibrariesCommand::HandleLibrary(const std::string& lib, if (tgt && (tgt->GetType() != cmStateEnums::STATIC_LIBRARY) && (tgt->GetType() != cmStateEnums::SHARED_LIBRARY) && (tgt->GetType() != cmStateEnums::UNKNOWN_LIBRARY) && + (tgt->GetType() != cmStateEnums::OBJECT_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."; + "INTERFACE, OBJECT, STATIC or SHARED libraries, or to executables " + "with the ENABLE_EXPORTS property set."; this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); } diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index ec31bd6..4bd07ef 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -28,6 +28,98 @@ static std::string cmVS10EscapeXML(std::string arg) return arg; } +struct cmVisualStudio10TargetGenerator::Elem +{ + cmGeneratedFileStream& S; + int Indent; + bool HasElements = false; + + Elem(cmGeneratedFileStream& s, int i) + : S(s) + , Indent(i) + { + } + Elem(const Elem&) = delete; + Elem(Elem& par) + : S(par.S) + , Indent(par.Indent + 1) + { + par.SetHasElements(); + } + void SetHasElements() + { + if (!HasElements) { + S << ">\n"; + HasElements = true; + } + } + void WriteEndTag(const char* tag) + { + if (HasElements) { + S.fill(' '); + S.width(Indent * 2); + // write an empty string to get the fill level indent to print + S << ""; + S << "</" << tag << ">\n"; + } else { + S << " />\n"; + } + } +}; + +class cmVS10GeneratorOptions : public cmVisualStudioGeneratorOptions +{ +public: + cmVS10GeneratorOptions(cmLocalVisualStudioGenerator* lg, Tool tool, + cmVS7FlagTable const* table, + cmVisualStudio10TargetGenerator* g = nullptr) + : cmVisualStudioGeneratorOptions(lg, tool, table) + , TargetGenerator(g) + { + } + + void OutputFlag(std::ostream& fout, const char* indent, const char* tag, + const std::string& content) override + { + if (!this->GetConfiguration().empty()) { + // if there are configuration specific flags, then + // use the configuration specific tag for PreprocessorDefinitions + fout << indent; + this->TargetGenerator->WritePlatformConfigTag( + tag, this->GetConfiguration(), 0); + } else { + fout << indent << "<" << tag << ">"; + } + fout << cmVS10EscapeXML(content); + fout << "</" << tag << ">\n"; + } + +private: + cmVisualStudio10TargetGenerator* TargetGenerator; +}; + +inline void cmVisualStudio10TargetGenerator::WriteElem(const char* tag, + const char* val, + int indentLevel) +{ + this->WriteString("<", indentLevel); + (*this->BuildFileStream) << tag << ">" << val << "</" << tag << ">\n"; +} + +inline void cmVisualStudio10TargetGenerator::WriteElem(const char* tag, + std::string const& val, + int indentLevel) +{ + this->WriteString("<", indentLevel); + (*this->BuildFileStream) << tag << ">" << val << "</" << tag << ">\n"; +} + +inline void cmVisualStudio10TargetGenerator::WriteElemEscapeXML( + const char* tag, std::string const& val, int indentLevel) +{ + this->WriteElem(tag, cmVS10EscapeXML(val), indentLevel); +} + static std::string cmVS10EscapeQuotes(std::string arg) { cmSystemTools::ReplaceString(arg, "\"", """); @@ -84,16 +176,15 @@ static std::string computeProjectFileExtension(cmGeneratorTarget const* t, cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator( cmGeneratorTarget* target, cmGlobalVisualStudio10Generator* gg) + : GeneratorTarget(target) + , Makefile(target->Target->GetMakefile()) + , Platform(gg->GetPlatformName()) + , Name(target->GetName()) + , GUID(gg->GetGUID(this->Name)) + , GlobalGenerator(gg) + , LocalGenerator((cmLocalVisualStudio7Generator*)target->GetLocalGenerator()) { - this->GlobalGenerator = gg; - this->GeneratorTarget = target; - this->Makefile = target->Target->GetMakefile(); this->Makefile->GetConfigurations(this->Configurations); - this->LocalGenerator = - (cmLocalVisualStudio7Generator*)this->GeneratorTarget->GetLocalGenerator(); - this->Name = this->GeneratorTarget->GetName(); - this->GUID = this->GlobalGenerator->GetGUID(this->Name); - this->Platform = gg->GetPlatformName(); this->NsightTegra = gg->IsNsightTegra(); for (int i = 0; i < 4; ++i) { this->NsightTegraVersion[i] = 0; @@ -127,12 +218,10 @@ cmVisualStudio10TargetGenerator::~cmVisualStudio10TargetGenerator() void cmVisualStudio10TargetGenerator::WritePlatformConfigTag( const char* tag, const std::string& config, int indentLevel, - const char* attribute, const char* end, std::ostream* stream) + const char* attribute) { - if (!stream) { - stream = this->BuildFileStream; - } + std::ostream* stream = this->BuildFileStream; stream->fill(' '); stream->width(indentLevel * 2); (*stream) << ""; // applies indentation @@ -153,8 +242,8 @@ void cmVisualStudio10TargetGenerator::WritePlatformConfigTag( } // close the tag (*stream) << ">"; - if (end) { - (*stream) << end; + if (attribute) { + (*stream) << "\n"; } } @@ -266,16 +355,10 @@ void cmVisualStudio10TargetGenerator::Generate() } (*this->BuildFileStream) << "</NsightTegraProjectRevisionNumber>\n"; // Tell newer versions to upgrade silently when loading. - this->WriteString("<NsightTegraUpgradeOnceWithoutPrompt>" - "true" - "</NsightTegraUpgradeOnceWithoutPrompt>\n", - 2); + this->WriteElem("NsightTegraUpgradeOnceWithoutPrompt", "true", 2); } else { // Require Nsight Tegra 1.6 for JCompile support. - this->WriteString("<NsightTegraProjectRevisionNumber>" - "7" - "</NsightTegraProjectRevisionNumber>\n", - 2); + this->WriteElem("NsightTegraProjectRevisionNumber", "7", 2); } this->WriteString("</PropertyGroup>\n", 1); } @@ -283,9 +366,7 @@ void cmVisualStudio10TargetGenerator::Generate() if (const char* hostArch = this->GlobalGenerator->GetPlatformToolsetHostArchitecture()) { this->WriteString("<PropertyGroup>\n", 1); - this->WriteString("<PreferredToolArchitecture>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(hostArch) - << "</PreferredToolArchitecture>\n"; + this->WriteElemEscapeXML("PreferredToolArchitecture", hostArch, 2); this->WriteString("</PropertyGroup>\n", 1); } @@ -293,8 +374,7 @@ void cmVisualStudio10TargetGenerator::Generate() this->WriteProjectConfigurations(); } this->WriteString("<PropertyGroup Label=\"Globals\">\n", 1); - this->WriteString("<ProjectGuid>", 2); - (*this->BuildFileStream) << "{" << this->GUID << "}</ProjectGuid>\n"; + this->WriteElem("ProjectGuid", "{" + this->GUID + "}", 2); if (this->MSTools && this->GeneratorTarget->GetType() <= cmStateEnums::GLOBAL_TARGET) { @@ -323,61 +403,45 @@ void cmVisualStudio10TargetGenerator::Generate() this->GeneratorTarget->GetProperty("VS_SCC_PROVIDER"); if (vsProjectName && vsLocalPath && vsProvider) { - this->WriteString("<SccProjectName>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(vsProjectName) - << "</SccProjectName>\n"; - this->WriteString("<SccLocalPath>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(vsLocalPath) - << "</SccLocalPath>\n"; - this->WriteString("<SccProvider>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(vsProvider) - << "</SccProvider>\n"; + this->WriteElemEscapeXML("SccProjectName", vsProjectName, 2); + this->WriteElemEscapeXML("SccLocalPath", vsLocalPath, 2); + this->WriteElemEscapeXML("SccProvider", vsProvider, 2); const char* vsAuxPath = this->GeneratorTarget->GetProperty("VS_SCC_AUXPATH"); if (vsAuxPath) { - this->WriteString("<SccAuxPath>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(vsAuxPath) - << "</SccAuxPath>\n"; + this->WriteElemEscapeXML("SccAuxPath", vsAuxPath, 2); } } if (this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_COMPONENT")) { - this->WriteString("<WinMDAssembly>true</WinMDAssembly>\n", 2); + this->WriteElem("WinMDAssembly", "true", 2); } const char* vsGlobalKeyword = this->GeneratorTarget->GetProperty("VS_GLOBAL_KEYWORD"); if (!vsGlobalKeyword) { - this->WriteString("<Keyword>Win32Proj</Keyword>\n", 2); + this->WriteElem("Keyword", "Win32Proj", 2); } else { - this->WriteString("<Keyword>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(vsGlobalKeyword) - << "</Keyword>\n"; + this->WriteElemEscapeXML("Keyword", vsGlobalKeyword, 2); } const char* vsGlobalRootNamespace = this->GeneratorTarget->GetProperty("VS_GLOBAL_ROOTNAMESPACE"); if (vsGlobalRootNamespace) { - this->WriteString("<RootNamespace>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(vsGlobalRootNamespace) - << "</RootNamespace>\n"; + this->WriteElemEscapeXML("RootNamespace", vsGlobalRootNamespace, 2); } - this->WriteString("<Platform>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(this->Platform) - << "</Platform>\n"; + this->WriteElemEscapeXML("Platform", this->Platform, 2); const char* projLabel = this->GeneratorTarget->GetProperty("PROJECT_LABEL"); if (!projLabel) { projLabel = this->Name.c_str(); } - this->WriteString("<ProjectName>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(projLabel) << "</ProjectName>\n"; + this->WriteElemEscapeXML("ProjectName", projLabel, 2); if (const char* targetFrameworkVersion = this->GeneratorTarget->GetProperty( "VS_DOTNET_TARGET_FRAMEWORK_VERSION")) { - this->WriteString("<TargetFrameworkVersion>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(targetFrameworkVersion) - << "</TargetFrameworkVersion>\n"; + this->WriteElemEscapeXML("TargetFrameworkVersion", targetFrameworkVersion, + 2); } // Disable the project upgrade prompt that is displayed the first time a @@ -385,9 +449,7 @@ void cmVisualStudio10TargetGenerator::Generate() // the IDE (respected by VS 2013 and above). if (this->GlobalGenerator->GetVersion() >= cmGlobalVisualStudioGenerator::VS12) { - this->WriteString("<VCProjectUpgraderObjectName>NoUpgrade" - "</VCProjectUpgraderObjectName>\n", - 2); + this->WriteElem("VCProjectUpgraderObjectName", "NoUpgrade", 2); } std::vector<std::string> keys = this->GeneratorTarget->GetPropertyKeys(); @@ -438,8 +500,7 @@ void cmVisualStudio10TargetGenerator::Generate() } outputType += "</OutputType>\n"; this->WriteString(outputType.c_str(), 2); - this->WriteString("<AppDesignerFolder>Properties</AppDesignerFolder>\n", - 2); + this->WriteElem("AppDesignerFolder", "Properties", 2); } this->WriteString("</PropertyGroup>\n", 1); @@ -602,8 +663,7 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReferences() if (!name.empty()) { std::string path = i.second.GetValue(); if (!cmsys::SystemTools::FileIsFullPath(path)) { - path = std::string(this->GeneratorTarget->Target->GetMakefile() - ->GetCurrentSourceDirectory()) + + path = std::string(this->Makefile->GetCurrentSourceDirectory()) + "/" + path; } ConvertToWindowsSlash(path); @@ -637,12 +697,8 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReference( { this->WriteString("<Reference Include=\"", 2); (*this->BuildFileStream) << cmVS10EscapeXML(ref) << "\">\n"; - this->WriteString("<CopyLocalSatelliteAssemblies>true" - "</CopyLocalSatelliteAssemblies>\n", - 3); - this->WriteString("<ReferenceOutputAssembly>true" - "</ReferenceOutputAssembly>\n", - 3); + this->WriteElem("CopyLocalSatelliteAssemblies", "true", 3); + this->WriteElem("ReferenceOutputAssembly", "true", 3); if (!hint.empty()) { const char* privateReference = "True"; if (const char* value = this->GeneratorTarget->GetProperty( @@ -651,10 +707,8 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReference( privateReference = "False"; } } - this->WriteString("<Private>", 3); - (*this->BuildFileStream) << privateReference << "</Private>\n"; - this->WriteString("<HintPath>", 3); - (*this->BuildFileStream) << hint << "</HintPath>\n"; + this->WriteElem("Private", privateReference, 3); + this->WriteElem("HintPath", hint, 3); } this->WriteDotNetReferenceCustomTags(ref); this->WriteString("</Reference>\n", 2); @@ -713,9 +767,8 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup() (*this->BuildFileStream) << obj << "\">\n"; if (this->ProjectType != csproj) { - this->WriteString("<DependentUpon>", 3); std::string hFileName = obj.substr(0, obj.find_last_of(".")) + ".h"; - (*this->BuildFileStream) << hFileName << "</DependentUpon>\n"; + this->WriteElem("DependentUpon", hFileName, 3); for (std::string const& i : this->Configurations) { this->WritePlatformConfigTag("LogicalName", i, 3); @@ -743,8 +796,7 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup() link = cmsys::SystemTools::GetFilenameName(obj); } if (!link.empty()) { - this->WriteString("<Link>", 3); - (*this->BuildFileStream) << link << "</Link>\n"; + this->WriteElem("Link", link, 3); } } // Determine if this is a generated resource from a .Designer.cs file @@ -758,9 +810,7 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup() generator = g; } if (!generator.empty()) { - this->WriteString("<Generator>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(generator) - << "</Generator>\n"; + this->WriteElemEscapeXML("Generator", generator, 3); if (designerResource.find(srcDir) == 0) { designerResource = designerResource.substr(srcDir.length() + 1); } else if (designerResource.find(binDir) == 0) { @@ -770,9 +820,7 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup() cmsys::SystemTools::GetFilenameName(designerResource); } ConvertToWindowsSlash(designerResource); - this->WriteString("<LastGenOutput>", 3); - (*this->BuildFileStream) << designerResource - << "</LastGenOutput>\n"; + this->WriteElem("LastGenOutput", designerResource, 3); } } const cmPropertyMap& props = oi->GetProperties(); @@ -807,7 +855,7 @@ void cmVisualStudio10TargetGenerator::WriteXamlFilesGroup() this->WriteString("<ItemGroup>\n", 1); for (cmSourceFile const* oi : xamlObjs) { std::string obj = oi->GetFullPath(); - std::string xamlType; + const char* xamlType; const char* xamlTypeProperty = oi->GetProperty("VS_XAML_TYPE"); if (xamlTypeProperty) { xamlType = xamlTypeProperty; @@ -815,7 +863,9 @@ void cmVisualStudio10TargetGenerator::WriteXamlFilesGroup() xamlType = "Page"; } - this->WriteSource(xamlType, oi, ">\n"); + Elem e2(*this->BuildFileStream, 2); + this->WriteSource(xamlType, oi); + e2.SetHasElements(); if (this->ProjectType == csproj && !this->InSourceBuild) { // add <Link> tag to written XAML source if necessary const std::string srcDir = this->Makefile->GetCurrentSourceDirectory(); @@ -830,13 +880,11 @@ void cmVisualStudio10TargetGenerator::WriteXamlFilesGroup() } if (!link.empty()) { ConvertToWindowsSlash(link); - this->WriteString("<Link>", 3); - (*this->BuildFileStream) << link << "</Link>\n"; + this->WriteElem("Link", link, 3); } } - this->WriteString("<SubType>Designer</SubType>\n", 3); - this->WriteString("</", 2); - (*this->BuildFileStream) << xamlType << ">\n"; + this->WriteElem("SubType", "Designer", 3); + e2.WriteEndTag(xamlType); } this->WriteString("</ItemGroup>\n", 1); } @@ -858,10 +906,7 @@ void cmVisualStudio10TargetGenerator::WriteTargetSpecificReferences() void cmVisualStudio10TargetGenerator::WriteTargetsFileReferences() { - for (std::vector<TargetsFileAndConfigs>::iterator i = - this->TargetsFileAndConfigsVec.begin(); - i != this->TargetsFileAndConfigsVec.end(); ++i) { - TargetsFileAndConfigs const& tac = *i; + for (TargetsFileAndConfigs const& tac : this->TargetsFileAndConfigsVec) { this->WriteString("<Import Project=\"", 3); (*this->BuildFileStream) << tac.File << "\" "; (*this->BuildFileStream) << "Condition=\""; @@ -896,11 +941,10 @@ void cmVisualStudio10TargetGenerator::WriteWinRTReferences() } if (!references.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) { this->WriteString("<Reference Include=\"", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(*ri) << "\">\n"; - this->WriteString("<IsWinMDFile>true</IsWinMDFile>\n", 3); + (*this->BuildFileStream) << cmVS10EscapeXML(ri) << "\">\n"; + this->WriteElem("IsWinMDFile", "true", 3); this->WriteString("</Reference>\n", 2); } this->WriteString("</ItemGroup>\n", 1); @@ -912,16 +956,11 @@ void cmVisualStudio10TargetGenerator::WriteWinRTReferences() void cmVisualStudio10TargetGenerator::WriteProjectConfigurations() { this->WriteString("<ItemGroup Label=\"ProjectConfigurations\">\n", 1); - for (std::vector<std::string>::const_iterator i = - this->Configurations.begin(); - i != this->Configurations.end(); ++i) { + for (std::string const& c : this->Configurations) { this->WriteString("<ProjectConfiguration Include=\"", 2); - (*this->BuildFileStream) << *i << "|" << this->Platform << "\">\n"; - this->WriteString("<Configuration>", 3); - (*this->BuildFileStream) << *i << "</Configuration>\n"; - this->WriteString("<Platform>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(this->Platform) - << "</Platform>\n"; + (*this->BuildFileStream) << c << "|" << this->Platform << "\">\n"; + this->WriteElem("Configuration", c, 3); + this->WriteElemEscapeXML("Platform", this->Platform, 3); this->WriteString("</ProjectConfiguration>\n", 2); } this->WriteString("</ItemGroup>\n", 1); @@ -929,11 +968,9 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurations() void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues() { - for (std::vector<std::string>::const_iterator i = - this->Configurations.begin(); - i != this->Configurations.end(); ++i) { - this->WritePlatformConfigTag("PropertyGroup", *i, 1, - " Label=\"Configuration\"", "\n"); + for (std::string const& c : this->Configurations) { + this->WritePlatformConfigTag("PropertyGroup", c, 1, + " Label=\"Configuration\""); if (this->ProjectType != csproj) { std::string configType = "<ConfigurationType>"; @@ -979,12 +1016,12 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues() if (this->MSTools) { if (!this->Managed) { - this->WriteMSToolConfigurationValues(*i); + this->WriteMSToolConfigurationValues(c); } else { - this->WriteMSToolConfigurationValuesManaged(*i); + this->WriteMSToolConfigurationValuesManaged(c); } } else if (this->NsightTegra) { - this->WriteNsightTegraConfigurationValues(*i); + this->WriteNsightTegraConfigurationValues(c); } this->WriteString("</PropertyGroup>\n", 1); @@ -994,11 +1031,8 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues() void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues( std::string const& config) { - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); - const char* mfcFlag = - this->GeneratorTarget->Target->GetMakefile()->GetDefinition( - "CMAKE_MFC_FLAG"); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; + const char* mfcFlag = this->Makefile->GetDefinition("CMAKE_MFC_FLAG"); if (mfcFlag) { std::string const mfcFlagValue = mfcFlag; @@ -1010,9 +1044,7 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues( useOfMfcValue = "Dynamic"; } } - std::string mfcLine = "<UseOfMfc>"; - mfcLine += useOfMfcValue + "</UseOfMfc>\n"; - this->WriteString(mfcLine.c_str(), 2); + this->WriteElem("UseOfMfc", useOfMfcValue, 2); } if ((this->GeneratorTarget->GetType() <= cmStateEnums::OBJECT_LIBRARY && @@ -1021,57 +1053,46 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues( this->GlobalGenerator->TargetsWindowsPhone() || this->GlobalGenerator->TargetsWindowsStore() || this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_EXTENSIONS")) { - this->WriteString("<CharacterSet>Unicode</CharacterSet>\n", 2); + this->WriteElem("CharacterSet", "Unicode", 2); } else if (this->GeneratorTarget->GetType() <= cmStateEnums::MODULE_LIBRARY && this->ClOptions[config]->UsingSBCS()) { - this->WriteString("<CharacterSet>NotSet</CharacterSet>\n", 2); + this->WriteElem("CharacterSet", "NotSet", 2); } else { - this->WriteString("<CharacterSet>MultiByte</CharacterSet>\n", 2); + this->WriteElem("CharacterSet", "MultiByte", 2); } if (const char* toolset = gg->GetPlatformToolset()) { - std::string pts = "<PlatformToolset>"; - pts += toolset; - pts += "</PlatformToolset>\n"; - this->WriteString(pts.c_str(), 2); + this->WriteElem("PlatformToolset", toolset, 2); } if (this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_COMPONENT") || this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_EXTENSIONS")) { - this->WriteString("<WindowsAppContainer>true" - "</WindowsAppContainer>\n", - 2); + this->WriteElem("WindowsAppContainer", "true", 2); } } void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesManaged( std::string const& config) { - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; Options& o = *(this->ClOptions[config]); if (o.IsDebug()) { - this->WriteString("<DebugSymbols>true</DebugSymbols>\n", 2); - this->WriteString("<DefineDebug>true</DefineDebug>\n", 2); + this->WriteElem("DebugSymbols", "true", 2); + this->WriteElem("DefineDebug", "true", 2); } std::string outDir = this->GeneratorTarget->GetDirectory(config) + "/"; ConvertToWindowsSlash(outDir); - this->WriteString("<OutputPath>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(outDir) << "</OutputPath>\n"; + this->WriteElemEscapeXML("OutputPath", outDir, 2); if (o.HasFlag("Platform")) { - this->WriteString("<PlatformTarget>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(o.GetFlag("Platform")) - << "</PlatformTarget>\n"; + this->WriteElemEscapeXML("PlatformTarget", o.GetFlag("Platform"), 2); o.RemoveFlag("Platform"); } if (const char* toolset = gg->GetPlatformToolset()) { - this->WriteString("<PlatformToolset>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(toolset) - << "</PlatformToolset>\n"; + this->WriteElemEscapeXML("PlatformToolset", toolset, 2); } std::string postfixName = cmSystemTools::UpperCase(config); @@ -1081,12 +1102,10 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesManaged( if (const char* postfix = this->GeneratorTarget->GetProperty(postfixName)) { assemblyName += postfix; } - this->WriteString("<AssemblyName>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(assemblyName) - << "</AssemblyName>\n"; + this->WriteElemEscapeXML("AssemblyName", assemblyName, 2); if (cmStateEnums::EXECUTABLE == this->GeneratorTarget->GetType()) { - this->WriteString("<StartAction>Program</StartAction>\n", 2); + this->WriteElem("StartAction", "Program", 2); this->WriteString("<StartProgram>", 2); (*this->BuildFileStream) << cmVS10EscapeXML(outDir) << cmVS10EscapeXML(assemblyName) @@ -1100,8 +1119,7 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesManaged( void cmVisualStudio10TargetGenerator::WriteNsightTegraConfigurationValues( std::string const&) { - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; const char* toolset = gg->GetPlatformToolset(); std::string ntv = "<NdkToolchainVersion>"; ntv += toolset ? toolset : "Default"; @@ -1109,27 +1127,20 @@ void cmVisualStudio10TargetGenerator::WriteNsightTegraConfigurationValues( this->WriteString(ntv.c_str(), 2); if (const char* minApi = this->GeneratorTarget->GetProperty("ANDROID_API_MIN")) { - this->WriteString("<AndroidMinAPI>", 2); - (*this->BuildFileStream) << "android-" << cmVS10EscapeXML(minApi) - << "</AndroidMinAPI>\n"; + this->WriteElem("AndroidMinAPI", "android-" + cmVS10EscapeXML(minApi), 2); } if (const char* api = this->GeneratorTarget->GetProperty("ANDROID_API")) { - this->WriteString("<AndroidTargetAPI>", 2); - (*this->BuildFileStream) << "android-" << cmVS10EscapeXML(api) - << "</AndroidTargetAPI>\n"; + this->WriteElem("AndroidTargetAPI", "android-" + cmVS10EscapeXML(api), 2); } if (const char* cpuArch = this->GeneratorTarget->GetProperty("ANDROID_ARCH")) { - this->WriteString("<AndroidArch>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(cpuArch) << "</AndroidArch>\n"; + this->WriteElemEscapeXML("AndroidArch", cpuArch, 2); } if (const char* stlType = this->GeneratorTarget->GetProperty("ANDROID_STL_TYPE")) { - this->WriteString("<AndroidStlType>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(stlType) - << "</AndroidStlType>\n"; + this->WriteElemEscapeXML("AndroidStlType", stlType, 2); } } @@ -1139,10 +1150,8 @@ void cmVisualStudio10TargetGenerator::WriteCustomCommands() this->CSharpCustomCommandNames.clear(); std::vector<cmSourceFile const*> customCommands; this->GeneratorTarget->GetCustomCommands(customCommands, ""); - for (std::vector<cmSourceFile const*>::const_iterator si = - customCommands.begin(); - si != customCommands.end(); ++si) { - this->WriteCustomCommand(*si); + for (cmSourceFile const* si : customCommands) { + this->WriteCustomCommand(si); } // Add CMakeLists.txt file with rule to re-run CMake for user convenience. @@ -1161,9 +1170,8 @@ void cmVisualStudio10TargetGenerator::WriteCustomCommand( if (this->SourcesVisited.insert(sf).second) { if (std::vector<cmSourceFile*> const* depends = this->GeneratorTarget->GetSourceDepends(sf)) { - for (std::vector<cmSourceFile*>::const_iterator di = depends->begin(); - di != depends->end(); ++di) { - this->WriteCustomCommand(*di); + for (cmSourceFile const* di : *depends) { + this->WriteCustomCommand(di); } } if (cmCustomCommand const* command = sf->GetCustomCommand()) { @@ -1186,10 +1194,10 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( // VS 10 will always rebuild a custom command attached to a .rule // file that doesn't exist so create the file explicitly. if (source->GetPropertyAsBool("__CMAKE_RULE")) { - if (!cmSystemTools::FileExists(sourcePath.c_str())) { + if (!cmSystemTools::FileExists(sourcePath)) { // Make sure the path exists for the file std::string path = cmSystemTools::GetFilenamePath(sourcePath); - cmSystemTools::MakeDirectory(path.c_str()); + cmSystemTools::MakeDirectory(path); cmsys::ofstream fout(sourcePath.c_str()); if (fout) { fout << "# generated from CMake\n"; @@ -1209,34 +1217,33 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( } cmLocalVisualStudio7Generator* lg = this->LocalGenerator; + Elem e2(*this->BuildFileStream, 2); if (this->ProjectType != csproj) { - this->WriteSource("CustomBuild", source, ">\n"); + this->WriteSource("CustomBuild", source); + e2.SetHasElements(); } else { this->WriteString("<ItemGroup>\n", 1); std::string link; this->GetCSharpSourceLink(source, link); - this->WriteSource("None", source, ">\n"); + this->WriteSource("None", source); + e2.SetHasElements(); if (!link.empty()) { - this->WriteString("<Link>", 3); - (*this->BuildFileStream) << link << "</Link>\n"; + this->WriteElem("Link", link, 3); } - this->WriteString("</None>\n", 2); + e2.WriteEndTag("None"); this->WriteString("</ItemGroup>\n", 1); } - for (std::vector<std::string>::const_iterator i = - this->Configurations.begin(); - i != this->Configurations.end(); ++i) { - cmCustomCommandGenerator ccg(command, *i, this->LocalGenerator); + for (std::string const& c : this->Configurations) { + cmCustomCommandGenerator ccg(command, c, lg); std::string comment = lg->ConstructComment(ccg); comment = cmVS10EscapeComment(comment); std::string script = cmVS10EscapeXML(lg->ConstructScript(ccg)); // input files for custom command std::stringstream inputs; inputs << cmVS10EscapeXML(source->GetFullPath()); - for (std::vector<std::string>::const_iterator d = ccg.GetDepends().begin(); - d != ccg.GetDepends().end(); ++d) { + for (std::string const& d : ccg.GetDepends()) { std::string dep; - if (this->LocalGenerator->GetRealDependency(*d, *i, dep)) { + if (lg->GetRealDependency(d, c, dep)) { ConvertToWindowsSlash(dep); inputs << ";" << cmVS10EscapeXML(dep); } @@ -1244,15 +1251,14 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( // output files for custom command std::stringstream outputs; const char* sep = ""; - for (std::vector<std::string>::const_iterator o = ccg.GetOutputs().begin(); - o != ccg.GetOutputs().end(); ++o) { - std::string out = *o; + for (std::string const& o : ccg.GetOutputs()) { + std::string out = o; ConvertToWindowsSlash(out); outputs << sep << cmVS10EscapeXML(out); sep = ";"; } if (this->ProjectType == csproj) { - std::string name = "CustomCommand_" + *i + "_" + + std::string name = "CustomCommand_" + c + "_" + cmSystemTools::ComputeStringMD5(sourcePath); std::string inputs_s = inputs.str(); std::string outputs_s = outputs.str(); @@ -1260,15 +1266,15 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( script = cmVS10EscapeQuotes(script); inputs_s = cmVS10EscapeQuotes(inputs_s); outputs_s = cmVS10EscapeQuotes(outputs_s); - this->WriteCustomRuleCSharp(*i, name, script, inputs_s, outputs_s, + this->WriteCustomRuleCSharp(c, name, script, inputs_s, outputs_s, comment); } else { - this->WriteCustomRuleCpp(*i, script, inputs.str(), outputs.str(), + this->WriteCustomRuleCpp(c, script, inputs.str(), outputs.str(), comment); } } if (this->ProjectType != csproj) { - this->WriteString("</CustomBuild>\n", 2); + e2.WriteEndTag("CustomBuild"); } } @@ -1304,8 +1310,7 @@ void cmVisualStudio10TargetGenerator::WriteCustomRuleCSharp( attributes << "\n Name=\"" << name << "\""; attributes << "\n Inputs=\"" << inputs << "\""; attributes << "\n Outputs=\"" << outputs << "\""; - this->WritePlatformConfigTag("Target", config, 1, attributes.str().c_str(), - "\n"); + this->WritePlatformConfigTag("Target", config, 1, attributes.str().c_str()); if (!comment.empty()) { this->WriteString("<Exec Command=\"", 2); (*this->BuildFileStream) << "echo " << cmVS10EscapeXML(comment) @@ -1321,8 +1326,8 @@ std::string cmVisualStudio10TargetGenerator::ConvertPath( { return forceRelative ? cmSystemTools::RelativePath( - this->LocalGenerator->GetCurrentBinaryDirectory(), path.c_str()) - : path.c_str(); + this->LocalGenerator->GetCurrentBinaryDirectory(), path) + : path; } static void ConvertToWindowsSlash(std::string& s) @@ -1334,6 +1339,7 @@ static void ConvertToWindowsSlash(std::string& s) pos++; } } + void cmVisualStudio10TargetGenerator::WriteGroups() { if (this->ProjectType == csproj) { @@ -1347,10 +1353,8 @@ void cmVisualStudio10TargetGenerator::WriteGroups() this->GeneratorTarget->GetAllConfigSources(); std::set<cmSourceGroup*> groupsUsed; - for (std::vector<cmGeneratorTarget::AllConfigSource>::const_iterator si = - sources.begin(); - si != sources.end(); ++si) { - std::string const& source = si->Source->GetFullPath(); + for (cmGeneratorTarget::AllConfigSource const& si : sources) { + std::string const& source = si.Source->GetFullPath(); cmSourceGroup* sourceGroup = this->Makefile->FindSourceGroup(source, sourceGroups); groupsUsed.insert(sourceGroup); @@ -1382,9 +1386,8 @@ void cmVisualStudio10TargetGenerator::WriteGroups() "xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n"); this->WriteString(project_defaults.c_str(), 0); - for (ToolSourceMap::const_iterator ti = this->Tools.begin(); - ti != this->Tools.end(); ++ti) { - this->WriteGroupSources(ti->first.c_str(), ti->second, sourceGroups); + for (auto const& ti : this->Tools) { + this->WriteGroupSources(ti.first.c_str(), ti.second, sourceGroups); } // Added files are images and the manifest. @@ -1396,23 +1399,23 @@ void cmVisualStudio10TargetGenerator::WriteGroups() if (fileName == "wmappmanifest.xml") { this->WriteString("<XML Include=\"", 2); (*this->BuildFileStream) << oi << "\">\n"; - this->WriteString("<Filter>Resource Files</Filter>\n", 3); + this->WriteElem("Filter", "Resource Files", 3); this->WriteString("</XML>\n", 2); } else if (cmSystemTools::GetFilenameExtension(fileName) == ".appxmanifest") { this->WriteString("<AppxManifest Include=\"", 2); (*this->BuildFileStream) << oi << "\">\n"; - this->WriteString("<Filter>Resource Files</Filter>\n", 3); + this->WriteElem("Filter", "Resource Files", 3); this->WriteString("</AppxManifest>\n", 2); } else if (cmSystemTools::GetFilenameExtension(fileName) == ".pfx") { this->WriteString("<None Include=\"", 2); (*this->BuildFileStream) << oi << "\">\n"; - this->WriteString("<Filter>Resource Files</Filter>\n", 3); + this->WriteElem("Filter", "Resource Files", 3); this->WriteString("</None>\n", 2); } else { this->WriteString("<Image Include=\"", 2); (*this->BuildFileStream) << oi << "\">\n"; - this->WriteString("<Filter>Resource Files</Filter>\n", 3); + this->WriteElem("Filter", "Resource Files", 3); this->WriteString("</Image>\n", 2); } } @@ -1428,7 +1431,7 @@ void cmVisualStudio10TargetGenerator::WriteGroups() this->WriteString("<EmbeddedResource Include=\"", 2); ConvertToWindowsSlash(obj); (*this->BuildFileStream) << cmVS10EscapeXML(obj) << "\">\n"; - this->WriteString("<Filter>Resource Files</Filter>\n", 3); + this->WriteElem("Filter", "Resource Files", 3); this->WriteString("</EmbeddedResource>\n", 2); } this->WriteString("</ItemGroup>\n", 1); @@ -1447,10 +1450,8 @@ void cmVisualStudio10TargetGenerator::WriteGroups() (*this->BuildFileStream) << name << "\">\n"; std::string guidName = "SG_Filter_"; guidName += name; - this->WriteString("<UniqueIdentifier>", 3); std::string guid = this->GlobalGenerator->GetGUID(guidName); - (*this->BuildFileStream) << "{" << guid << "}" - << "</UniqueIdentifier>\n"; + this->WriteElem("UniqueIdentifier", "{" + guid + "}", 3); this->WriteString("</Filter>\n", 2); } } @@ -1458,10 +1459,8 @@ void cmVisualStudio10TargetGenerator::WriteGroups() if (!resxObjs.empty() || !this->AddedFiles.empty()) { this->WriteString("<Filter Include=\"Resource Files\">\n", 2); std::string guidName = "SG_Filter_Resource Files"; - this->WriteString("<UniqueIdentifier>", 3); std::string guid = this->GlobalGenerator->GetGUID(guidName); - (*this->BuildFileStream) << "{" << guid << "}" - << "</UniqueIdentifier>\n"; + this->WriteElem("UniqueIdentifier", "{" + guid + "}", 3); this->WriteString("<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;", 3); (*this->BuildFileStream) << "gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;"; (*this->BuildFileStream) << "mfcribbon-ms</Extensions>\n"; @@ -1516,7 +1515,7 @@ void cmVisualStudio10TargetGenerator::AddMissingSourceGroups( } void cmVisualStudio10TargetGenerator::WriteGroupSources( - const char* name, ToolSources const& sources, + std::string const& name, ToolSources const& sources, std::vector<cmSourceGroup>& sourceGroups) { this->WriteString("<ItemGroup>\n", 1); @@ -1532,8 +1531,7 @@ void cmVisualStudio10TargetGenerator::WriteGroupSources( (*this->BuildFileStream) << name << " Include=\"" << cmVS10EscapeXML(path); if (!filter.empty()) { (*this->BuildFileStream) << "\">\n"; - this->WriteString("<Filter>", 3); - (*this->BuildFileStream) << filter << "</Filter>\n"; + this->WriteElem("Filter", filter, 3); this->WriteString("</", 2); (*this->BuildFileStream) << name << ">\n"; } else { @@ -1546,25 +1544,23 @@ void cmVisualStudio10TargetGenerator::WriteGroupSources( void cmVisualStudio10TargetGenerator::WriteHeaderSource(cmSourceFile const* sf) { std::string const& fileName = sf->GetFullPath(); + Elem e2(*this->BuildFileStream, 2); + this->WriteSource("ClInclude", sf); if (this->IsResxHeader(fileName)) { - this->WriteSource("ClInclude", sf, ">\n"); - this->WriteString("<FileType>CppForm</FileType>\n", 3); - this->WriteString("</ClInclude>\n", 2); + e2.SetHasElements(); + this->WriteElem("FileType", "CppForm", 3); } else if (this->IsXamlHeader(fileName)) { - this->WriteSource("ClInclude", sf, ">\n"); - this->WriteString("<DependentUpon>", 3); std::string xamlFileName = fileName.substr(0, fileName.find_last_of(".")); - (*this->BuildFileStream) << xamlFileName << "</DependentUpon>\n"; - this->WriteString("</ClInclude>\n", 2); - } else { - this->WriteSource("ClInclude", sf); + e2.SetHasElements(); + this->WriteElem("DependentUpon", xamlFileName, 3); } + e2.WriteEndTag("ClInclude"); } void cmVisualStudio10TargetGenerator::WriteExtraSource(cmSourceFile const* sf) { bool toolHasSettings = false; - std::string tool = "None"; + const char* tool = "None"; std::string shaderType; std::string shaderEntryPoint; std::string shaderModel; @@ -1714,8 +1710,10 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(cmSourceFile const* sf) } } + Elem e2(*this->BuildFileStream, 2); + this->WriteSource(tool, sf); if (toolHasSettings) { - this->WriteSource(tool, sf, ">\n"); + e2.SetHasElements(); if (!deployContent.empty()) { cmGeneratorExpression ge; @@ -1749,19 +1747,13 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(cmSourceFile const* sf) } } if (!shaderType.empty()) { - this->WriteString("<ShaderType>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(shaderType) - << "</ShaderType>\n"; + this->WriteElemEscapeXML("ShaderType", shaderType, 3); } if (!shaderEntryPoint.empty()) { - this->WriteString("<EntryPointName>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(shaderEntryPoint) - << "</EntryPointName>\n"; + this->WriteElemEscapeXML("EntryPointName", shaderEntryPoint, 3); } if (!shaderModel.empty()) { - this->WriteString("<ShaderModel>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(shaderModel) - << "</ShaderModel>\n"; + this->WriteElemEscapeXML("ShaderModel", shaderModel, 3); } if (!outputHeaderFile.empty()) { for (size_t i = 0; i != this->Configurations.size(); ++i) { @@ -1786,60 +1778,42 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(cmSourceFile const* sf) } } if (!shaderEnableDebug.empty()) { - this->WriteString("<EnableDebuggingInformation>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(shaderEnableDebug) - << "</EnableDebuggingInformation>\n"; + this->WriteElemEscapeXML("EnableDebuggingInformation", shaderEnableDebug, + 3); } if (!shaderDisableOptimizations.empty()) { - this->WriteString("<DisableOptimizations>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(shaderDisableOptimizations) - << "</DisableOptimizations>\n"; + this->WriteElemEscapeXML("DisableOptimizations", + shaderDisableOptimizations, 3); } if (!shaderAdditionalFlags.empty()) { - this->WriteString("<AdditionalOptions>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(shaderAdditionalFlags) - << "</AdditionalOptions>\n"; + this->WriteElemEscapeXML("AdditionalOptions", shaderAdditionalFlags, 3); } if (!settingsGenerator.empty()) { - this->WriteString("<Generator>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(settingsGenerator) - << "</Generator>\n"; + this->WriteElemEscapeXML("Generator", settingsGenerator, 3); } if (!settingsLastGenOutput.empty()) { - this->WriteString("<LastGenOutput>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(settingsLastGenOutput) - << "</LastGenOutput>\n"; + this->WriteElemEscapeXML("LastGenOutput", settingsLastGenOutput, 3); } if (!sourceLink.empty()) { - this->WriteString("<Link>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(sourceLink) << "</Link>\n"; + this->WriteElemEscapeXML("Link", sourceLink, 3); } if (!subType.empty()) { - this->WriteString("<SubType>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(subType) << "</SubType>\n"; + this->WriteElemEscapeXML("SubType", subType, 3); } if (!copyToOutDir.empty()) { - this->WriteString("<CopyToOutputDirectory>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(copyToOutDir) - << "</CopyToOutputDirectory>\n"; + this->WriteElemEscapeXML("CopyToOutputDirectory", copyToOutDir, 3); } if (!includeInVsix.empty()) { - this->WriteString("<IncludeInVSIX>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(includeInVsix) - << "</IncludeInVSIX>\n"; + this->WriteElemEscapeXML("IncludeInVSIX", includeInVsix, 3); } // write source file specific tags this->WriteCSharpSourceProperties(sourceFileTags); - this->WriteString("</", 2); - (*this->BuildFileStream) << tool << ">\n"; - } else { - this->WriteSource(tool, sf); } + e2.WriteEndTag(tool); } void cmVisualStudio10TargetGenerator::WriteSource(std::string const& tool, - cmSourceFile const* sf, - const char* end) + cmSourceFile const* sf) { // Visual Studio tools append relative paths to the current dir, as in: // @@ -1853,7 +1827,7 @@ void cmVisualStudio10TargetGenerator::WriteSource(std::string const& tool, std::string sourceFile = this->ConvertPath(sf->GetFullPath(), forceRelative); if (this->LocalGenerator->GetVersion() == cmGlobalVisualStudioGenerator::VS10 && - cmSystemTools::FileIsFullPath(sourceFile.c_str())) { + cmSystemTools::FileIsFullPath(sourceFile)) { // Normal path conversion resulted in a full path. VS 10 (but not 11) // refuses to show the property page in the IDE for a source file with a // full path (not starting in a '.' or '/' AFAICT). CMake <= 2.8.4 used a @@ -1876,8 +1850,7 @@ void cmVisualStudio10TargetGenerator::WriteSource(std::string const& tool, ConvertToWindowsSlash(sourceFile); this->WriteString("<", 2); (*this->BuildFileStream) << tool << " Include=\"" - << cmVS10EscapeXML(sourceFile) << "\"" - << (end ? end : " />\n"); + << cmVS10EscapeXML(sourceFile) << "\""; ToolSource toolSource = { sf, forceRelative }; this->Tools[tool].push_back(toolSource); @@ -1899,7 +1872,7 @@ void cmVisualStudio10TargetGenerator::WriteAllSources() this->GeneratorTarget->GetAllConfigSources(); for (cmGeneratorTarget::AllConfigSource const& si : sources) { - std::string tool; + const char* tool = nullptr; switch (si.Kind) { case cmGeneratorTarget::SourceKindAppManifest: tool = "AppxManifest"; @@ -1968,7 +1941,7 @@ void cmVisualStudio10TargetGenerator::WriteAllSources() break; } - if (!tool.empty()) { + if (tool) { // Compute set of configurations to exclude, if any. std::vector<size_t> const& include_configs = si.Configs; std::vector<size_t> exclude_configs; @@ -1976,31 +1949,15 @@ void cmVisualStudio10TargetGenerator::WriteAllSources() include_configs.begin(), include_configs.end(), std::back_inserter(exclude_configs)); + Elem e2(*this->BuildFileStream, 2); + this->WriteSource(tool, si.Source); 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); - if (!exclude_configs.empty()) { - if (!have_nested) { - (*this->BuildFileStream) << ">\n"; - } - this->WriteExcludeFromBuild(exclude_configs); - have_nested = true; - } - if (have_nested) { - this->WriteString("</", 2); - (*this->BuildFileStream) << tool << ">\n"; - } else { - (*this->BuildFileStream) << " />\n"; - } - } else if (!exclude_configs.empty()) { - this->WriteSource(tool, si.Source, ">\n"); - this->WriteExcludeFromBuild(exclude_configs); - this->WriteString("</", 2); - (*this->BuildFileStream) << tool << ">\n"; - } else { - this->WriteSource(tool, si.Source); + this->OutputSourceSpecificFlags(e2, si.Source); } + if (!exclude_configs.empty()) { + this->WriteExcludeFromBuild(e2, exclude_configs); + } + e2.WriteEndTag(tool); } } @@ -2011,8 +1968,8 @@ void cmVisualStudio10TargetGenerator::WriteAllSources() this->WriteString("</ItemGroup>\n", 1); } -bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( - cmSourceFile const* source) +void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( + Elem& e2, cmSourceFile const* source) { cmSourceFile const& sf = *source; @@ -2072,22 +2029,14 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( } } bool noWinRT = this->TargetCompileAsWinRT && lang == "C"; - bool hasFlags = false; // for the first time we need a new line if there is something // produced here. - const char* firstString = ">\n"; if (!objectName.empty()) { - (*this->BuildFileStream) << firstString; - firstString = ""; - hasFlags = true; + e2.SetHasElements(); if (lang == "CUDA") { - this->WriteString("<CompileOut>", 3); - (*this->BuildFileStream) << "$(IntDir)/" << objectName - << "</CompileOut>\n"; + this->WriteElem("CompileOut", "$(IntDir)/" + objectName, 3); } else { - this->WriteString("<ObjectFileName>", 3); - (*this->BuildFileStream) << "$(IntDir)/" << objectName - << "</ObjectFileName>\n"; + this->WriteElem("ObjectFileName", "$(IntDir)/" + objectName, 3); } } for (std::string const& config : this->Configurations) { @@ -2107,11 +2056,8 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( // use them if (!flags.empty() || !options.empty() || !configDefines.empty() || !includes.empty() || compileAs || noWinRT) { - (*this->BuildFileStream) << firstString; - firstString = ""; // only do firstString once - hasFlags = true; - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); + e2.SetHasElements(); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; cmIDEFlagTable const* flagtable = nullptr; const std::string& srclang = source->GetLanguage(); if (srclang == "C" || srclang == "CXX") { @@ -2130,9 +2076,9 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( cmGeneratorExpressionInterpreter genexInterpreter( this->LocalGenerator, this->GeneratorTarget, config, this->GeneratorTarget->GetName(), lang); - cmVisualStudioGeneratorOptions clOptions( + cmVS10GeneratorOptions clOptions( this->LocalGenerator, cmVisualStudioGeneratorOptions::Compiler, - flagtable, 0, this); + flagtable, this); if (compileAs) { clOptions.AddFlag("CompileAs", compileAs); } @@ -2163,7 +2109,7 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( clOptions.AddDefines( genexInterpreter.Evaluate(configDefines, "COMPILE_DEFINITIONS")); } else { - clOptions.AddDefines(configDefines.c_str()); + clOptions.AddDefines(configDefines); } std::vector<std::string> includeList; if (configDependentIncludes) { @@ -2175,23 +2121,20 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( *source); } clOptions.AddIncludes(includeList); - clOptions.SetConfiguration(config.c_str()); + clOptions.SetConfiguration(config); clOptions.PrependInheritedString("AdditionalOptions"); clOptions.OutputAdditionalIncludeDirectories(*this->BuildFileStream, - " ", "\n", lang); + " ", lang); clOptions.OutputFlagMap(*this->BuildFileStream, " "); clOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ", - "\n", lang); + lang); } } if (this->IsXamlSource(source->GetFullPath())) { - (*this->BuildFileStream) << firstString; - firstString = ""; // only do firstString once - hasFlags = true; - this->WriteString("<DependentUpon>", 3); + e2.SetHasElements(); const std::string& fileName = source->GetFullPath(); std::string xamlFileName = fileName.substr(0, fileName.find_last_of(".")); - (*this->BuildFileStream) << xamlFileName << "</DependentUpon>\n"; + this->WriteElem("DependentUpon", xamlFileName, 3); } if (this->ProjectType == csproj) { std::string f = source->GetFullPath(); @@ -2206,19 +2149,16 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( this->GetCSharpSourceProperties(&sf, sourceFileTags); // write source file specific tags if (!sourceFileTags.empty()) { - hasFlags = true; - (*this->BuildFileStream) << firstString; - firstString = ""; + e2.SetHasElements(); this->WriteCSharpSourceProperties(sourceFileTags); } } - - return hasFlags; } void cmVisualStudio10TargetGenerator::WriteExcludeFromBuild( - std::vector<size_t> const& exclude_configs) + Elem& e2, std::vector<size_t> const& exclude_configs) { + e2.SetHasElements(); for (size_t ci : exclude_configs) { this->WriteString("", 3); (*this->BuildFileStream) @@ -2239,9 +2179,7 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions() } this->WriteString("<PropertyGroup>\n", 1); - this->WriteString("<_ProjectFileVersion>10.0.20506.1" - "</_ProjectFileVersion>\n", - 2); + this->WriteElem("_ProjectFileVersion", "10.0.20506.1", 2); for (std::string const& config : this->Configurations) { if (ttype >= cmStateEnums::UTILITY) { this->WritePlatformConfigTag("IntDir", config, 2); @@ -2282,6 +2220,13 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions() << "</LocalDebuggerWorkingDirectory>\n"; } + if (const char* debuggerCommand = + this->GeneratorTarget->GetProperty("VS_DEBUGGER_COMMAND")) { + this->WritePlatformConfigTag("LocalDebuggerCommand", config, 2); + *this->BuildFileStream << cmVS10EscapeXML(debuggerCommand) + << "</LocalDebuggerCommand>\n"; + } + std::string name = cmSystemTools::GetFilenameWithoutLastExtension(targetNameFull); this->WritePlatformConfigTag("TargetName", config, 2); @@ -2374,8 +2319,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( // copied from cmLocalVisualStudio7Generator.cxx 805 // TODO: Integrate code below with cmLocalVisualStudio7Generator. - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; std::unique_ptr<Options> pOptions; switch (this->ProjectType) { case vcxproj: @@ -2422,15 +2366,11 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( std::string baseFlagVar = "CMAKE_"; baseFlagVar += langForClCompile; baseFlagVar += "_FLAGS"; - flags = - this->GeneratorTarget->Target->GetMakefile()->GetRequiredDefinition( - baseFlagVar); + flags = this->Makefile->GetRequiredDefinition(baseFlagVar); std::string flagVar = baseFlagVar + std::string("_") + cmSystemTools::UpperCase(configName); flags += " "; - flags += - this->GeneratorTarget->Target->GetMakefile()->GetRequiredDefinition( - flagVar); + flags += this->Makefile->GetRequiredDefinition(flagVar); this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget, langForClCompile, configName); } @@ -2446,8 +2386,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( this->GeneratorTarget->IsIPOEnabled(linkLanguage, configName); // Get preprocessor definitions for this directory. - std::string defineFlags = - this->GeneratorTarget->Target->GetMakefile()->GetDefineFlags(); + std::string defineFlags = this->Makefile->GetDefineFlags(); if (this->MSTools) { if (this->ProjectType == vcxproj) { clOptions.FixExceptionHandlingDefault(); @@ -2544,17 +2483,15 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( this->WriteString("<ClCompile>\n", 2); clOptions.PrependInheritedString("AdditionalOptions"); clOptions.OutputAdditionalIncludeDirectories( - *this->BuildFileStream, " ", "\n", this->LangForClCompile); + *this->BuildFileStream, " ", this->LangForClCompile); clOptions.OutputFlagMap(*this->BuildFileStream, " "); clOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ", - "\n", this->LangForClCompile); + this->LangForClCompile); if (this->NsightTegra) { if (const char* processMax = this->GeneratorTarget->GetProperty("ANDROID_PROCESS_MAX")) { - this->WriteString("<ProcessMax>", 3); - *this->BuildFileStream << cmVS10EscapeXML(processMax) - << "</ProcessMax>\n"; + this->WriteElemEscapeXML("ProcessMax", processMax, 3); } } @@ -2562,12 +2499,9 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( cmsys::RegularExpression clangToolset("v[0-9]+_clang_.*"); const char* toolset = this->GlobalGenerator->GetPlatformToolset(); if (toolset && clangToolset.find(toolset)) { - this->WriteString("<ObjectFileName>" - "$(IntDir)%(filename).obj" - "</ObjectFileName>\n", - 3); + this->WriteElem("ObjectFileName", "$(IntDir)%(filename).obj", 3); } else { - this->WriteString("<ObjectFileName>$(IntDir)</ObjectFileName>\n", 3); + this->WriteElem("ObjectFileName", "$(IntDir)", 3); } // If not in debug mode, write the DebugInformationFormat field @@ -2583,9 +2517,7 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( std::string pdb = this->GeneratorTarget->GetCompilePDBPath(configName); if (!pdb.empty()) { ConvertToWindowsSlash(pdb); - this->WriteString("<ProgramDataBaseFileName>", 3); - *this->BuildFileStream << cmVS10EscapeXML(pdb) - << "</ProgramDataBaseFileName>\n"; + this->WriteElemEscapeXML("ProgramDataBaseFileName", pdb, 3); } } @@ -2605,8 +2537,7 @@ bool cmVisualStudio10TargetGenerator::ComputeRcOptions() bool cmVisualStudio10TargetGenerator::ComputeRcOptions( std::string const& configName) { - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; auto pOptions = cm::make_unique<Options>( this->LocalGenerator, Options::ResourceCompiler, gg->GetRcFlagTable()); Options& rcOptions = *pOptions; @@ -2641,9 +2572,9 @@ void cmVisualStudio10TargetGenerator::WriteRCOptions( Options& rcOptions = *(this->RcOptions[configName]); rcOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ", - "\n", "RC"); + "RC"); rcOptions.OutputAdditionalIncludeDirectories(*this->BuildFileStream, - " ", "\n", "RC"); + " ", "RC"); rcOptions.PrependInheritedString("AdditionalOptions"); rcOptions.OutputFlagMap(*this->BuildFileStream, " "); @@ -2666,8 +2597,7 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions() bool cmVisualStudio10TargetGenerator::ComputeCudaOptions( std::string const& configName) { - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; auto pOptions = cm::make_unique<Options>( this->LocalGenerator, Options::CudaCompiler, gg->GetCudaFlagTable()); Options& cudaOptions = *pOptions; @@ -2683,8 +2613,7 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions( configName); // Get preprocessor definitions for this directory. - std::string defineFlags = - this->GeneratorTarget->Target->GetMakefile()->GetDefineFlags(); + std::string defineFlags = this->Makefile->GetDefineFlags(); cudaOptions.Parse(flags.c_str()); cudaOptions.Parse(defineFlags.c_str()); @@ -2779,9 +2708,9 @@ void cmVisualStudio10TargetGenerator::WriteCudaOptions( Options& cudaOptions = *(this->CudaOptions[configName]); cudaOptions.OutputAdditionalIncludeDirectories(*this->BuildFileStream, - " ", "\n", "CUDA"); + " ", "CUDA"); cudaOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ", - "\n", "CUDA"); + "CUDA"); cudaOptions.PrependInheritedString("AdditionalOptions"); cudaOptions.OutputFlagMap(*this->BuildFileStream, " "); @@ -2804,8 +2733,7 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions() bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions( std::string const& configName) { - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; auto pOptions = cm::make_unique<Options>( this->LocalGenerator, Options::CudaCompiler, gg->GetCudaFlagTable()); Options& cudaLinkOptions = *pOptions; @@ -2873,8 +2801,7 @@ bool cmVisualStudio10TargetGenerator::ComputeMasmOptions() bool cmVisualStudio10TargetGenerator::ComputeMasmOptions( std::string const& configName) { - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; auto pOptions = cm::make_unique<Options>( this->LocalGenerator, Options::MasmCompiler, gg->GetMasmFlagTable()); Options& masmOptions = *pOptions; @@ -2906,11 +2833,11 @@ void cmVisualStudio10TargetGenerator::WriteMasmOptions( // Preprocessor definitions and includes are shared with clOptions. Options& clOptions = *(this->ClOptions[configName]); clOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ", - "\n", "ASM_MASM"); + "ASM_MASM"); Options& masmOptions = *(this->MasmOptions[configName]); masmOptions.OutputAdditionalIncludeDirectories(*this->BuildFileStream, - " ", "\n", "ASM_MASM"); + " ", "ASM_MASM"); masmOptions.PrependInheritedString("AdditionalOptions"); masmOptions.OutputFlagMap(*this->BuildFileStream, " "); @@ -2933,8 +2860,7 @@ bool cmVisualStudio10TargetGenerator::ComputeNasmOptions() bool cmVisualStudio10TargetGenerator::ComputeNasmOptions( std::string const& configName) { - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; auto pOptions = cm::make_unique<Options>( this->LocalGenerator, Options::NasmCompiler, gg->GetNasmFlagTable()); Options& nasmOptions = *pOptions; @@ -2968,16 +2894,16 @@ void cmVisualStudio10TargetGenerator::WriteNasmOptions( this->GetIncludes(configName, "ASM_NASM"); Options& nasmOptions = *(this->NasmOptions[configName]); nasmOptions.OutputAdditionalIncludeDirectories(*this->BuildFileStream, - " ", "\n", "ASM_NASM"); + " ", "ASM_NASM"); nasmOptions.OutputFlagMap(*this->BuildFileStream, " "); nasmOptions.PrependInheritedString("AdditionalOptions"); nasmOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ", - "\n", "ASM_NASM"); + "ASM_NASM"); // Preprocessor definitions and includes are shared with clOptions. Options& clOptions = *(this->ClOptions[configName]); clOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ", - "\n", "ASM_NASM"); + "ASM_NASM"); this->WriteString("</NASM>\n", 2); } @@ -2994,11 +2920,10 @@ void cmVisualStudio10TargetGenerator::WriteLibOptions( libflags, cmSystemTools::UpperCase(config), this->GeneratorTarget); if (!libflags.empty()) { this->WriteString("<Lib>\n", 2); - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); - cmVisualStudioGeneratorOptions libOptions( - this->LocalGenerator, cmVisualStudioGeneratorOptions::Linker, - gg->GetLibFlagTable(), 0, this); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; + cmVS10GeneratorOptions libOptions(this->LocalGenerator, + cmVisualStudioGeneratorOptions::Linker, + gg->GetLibFlagTable(), this); libOptions.Parse(libflags.c_str()); libOptions.PrependInheritedString("AdditionalOptions"); libOptions.OutputFlagMap(*this->BuildFileStream, " "); @@ -3011,9 +2936,7 @@ void cmVisualStudio10TargetGenerator::WriteLibOptions( if (this->GlobalGenerator->TargetsWindowsPhone() || this->GlobalGenerator->TargetsWindowsStore()) { this->WriteString("<Link>\n", 2); - this->WriteString("<GenerateWindowsMetadata>false" - "</GenerateWindowsMetadata>\n", - 3); + this->WriteElem("GenerateWindowsMetadata", "false", 3); this->WriteString("</Link>\n", 2); } } @@ -3064,32 +2987,28 @@ void cmVisualStudio10TargetGenerator::WriteAntBuildOptions( { std::string antBuildPath = rootDir; this->WriteString("<AntBuild>\n", 2); - this->WriteString("<AntBuildPath>", 3); ConvertToWindowsSlash(antBuildPath); - (*this->BuildFileStream) << cmVS10EscapeXML(antBuildPath) - << "</AntBuildPath>\n"; + this->WriteElemEscapeXML("AntBuildPath", antBuildPath, 3); } if (this->GeneratorTarget->GetPropertyAsBool("ANDROID_SKIP_ANT_STEP")) { - this->WriteString("<SkipAntStep>true</SkipAntStep>\n", 3); + this->WriteElem("SkipAntStep", "true", 3); } if (this->GeneratorTarget->GetPropertyAsBool("ANDROID_PROGUARD")) { - this->WriteString("<EnableProGuard>true</EnableProGuard>\n", 3); + this->WriteElem("EnableProGuard", "true", 3); } if (const char* proGuardConfigLocation = this->GeneratorTarget->GetProperty("ANDROID_PROGUARD_CONFIG_PATH")) { - this->WriteString("<ProGuardConfigLocation>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(proGuardConfigLocation) - << "</ProGuardConfigLocation>\n"; + this->WriteElemEscapeXML("ProGuardConfigLocation", proGuardConfigLocation, + 3); } if (const char* securePropertiesLocation = this->GeneratorTarget->GetProperty("ANDROID_SECURE_PROPS_PATH")) { - this->WriteString("<SecurePropertiesLocation>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(securePropertiesLocation) - << "</SecurePropertiesLocation>\n"; + this->WriteElemEscapeXML("SecurePropertiesLocation", + securePropertiesLocation, 3); } if (const char* nativeLibDirectoriesExpression = @@ -3099,9 +3018,7 @@ void cmVisualStudio10TargetGenerator::WriteAntBuildOptions( ge.Parse(nativeLibDirectoriesExpression); std::string nativeLibDirs = cge->Evaluate(this->LocalGenerator, configName); - this->WriteString("<NativeLibDirectories>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(nativeLibDirs) - << "</NativeLibDirectories>\n"; + this->WriteElemEscapeXML("NativeLibDirectories", nativeLibDirs, 3); } if (const char* nativeLibDependenciesExpression = @@ -3112,16 +3029,12 @@ void cmVisualStudio10TargetGenerator::WriteAntBuildOptions( ge.Parse(nativeLibDependenciesExpression); std::string nativeLibDeps = cge->Evaluate(this->LocalGenerator, configName); - this->WriteString("<NativeLibDependencies>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(nativeLibDeps) - << "</NativeLibDependencies>\n"; + this->WriteElemEscapeXML("NativeLibDependencies", nativeLibDeps, 3); } if (const char* javaSourceDir = this->GeneratorTarget->GetProperty("ANDROID_JAVA_SOURCE_DIR")) { - this->WriteString("<JavaSourceDir>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(javaSourceDir) - << "</JavaSourceDir>\n"; + this->WriteElemEscapeXML("JavaSourceDir", javaSourceDir, 3); } if (const char* jarDirectoriesExpression = @@ -3131,31 +3044,23 @@ void cmVisualStudio10TargetGenerator::WriteAntBuildOptions( ge.Parse(jarDirectoriesExpression); std::string jarDirectories = cge->Evaluate(this->LocalGenerator, configName); - this->WriteString("<JarDirectories>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(jarDirectories) - << "</JarDirectories>\n"; + this->WriteElemEscapeXML("JarDirectories", jarDirectories, 3); } if (const char* jarDeps = this->GeneratorTarget->GetProperty("ANDROID_JAR_DEPENDENCIES")) { - this->WriteString("<JarDependencies>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(jarDeps) - << "</JarDependencies>\n"; + this->WriteElemEscapeXML("JarDependencies", jarDeps, 3); } if (const char* assetsDirectories = this->GeneratorTarget->GetProperty("ANDROID_ASSETS_DIRECTORIES")) { - this->WriteString("<AssetsDirectories>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(assetsDirectories) - << "</AssetsDirectories>\n"; + this->WriteElemEscapeXML("AssetsDirectories", assetsDirectories, 3); } { std::string manifest_xml = rootDir + "/AndroidManifest.xml"; ConvertToWindowsSlash(manifest_xml); - this->WriteString("<AndroidManifestLocation>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(manifest_xml) - << "</AndroidManifestLocation>\n"; + this->WriteElemEscapeXML("AndroidManifestLocation", manifest_xml, 3); } if (const char* antAdditionalOptions = @@ -3185,11 +3090,9 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions() bool cmVisualStudio10TargetGenerator::ComputeLinkOptions( std::string const& config) { - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); - auto pOptions = - cm::make_unique<Options>(this->LocalGenerator, Options::Linker, - gg->GetLinkFlagTable(), nullptr, this); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; + auto pOptions = cm::make_unique<Options>( + this->LocalGenerator, Options::Linker, gg->GetLinkFlagTable(), this); Options& linkOptions = *pOptions; cmGeneratorTarget::LinkClosure const* linkClosure = @@ -3217,12 +3120,10 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions( linkFlagVarBase += linkType; linkFlagVarBase += "_LINKER_FLAGS"; flags += " "; - flags += this->GeneratorTarget->Target->GetMakefile()->GetRequiredDefinition( - linkFlagVarBase); + flags += this->Makefile->GetRequiredDefinition(linkFlagVarBase); std::string linkFlagVar = linkFlagVarBase + "_" + CONFIG; flags += " "; - flags += this->GeneratorTarget->Target->GetMakefile()->GetRequiredDefinition( - linkFlagVar); + flags += this->Makefile->GetRequiredDefinition(linkFlagVar); const char* targetLinkFlags = this->GeneratorTarget->GetProperty("LINK_FLAGS"); if (targetLinkFlags) { @@ -3376,7 +3277,7 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions( cmGeneratorTarget::ModuleDefinitionInfo const* mdi = this->GeneratorTarget->GetModuleDefinitionInfo(config); if (mdi && !mdi->DefFile.empty()) { - linkOptions.AddFlag("ModuleDefinitionFile", mdi->DefFile.c_str()); + linkOptions.AddFlag("ModuleDefinitionFile", mdi->DefFile); } linkOptions.AppendFlag("IgnoreSpecificDefaultLibraries", "%(IgnoreSpecificDefaultLibraries)"); @@ -3459,8 +3360,7 @@ void cmVisualStudio10TargetGenerator::WriteLinkOptions( if (!this->GlobalGenerator->NeedLinkLibraryDependencies( this->GeneratorTarget)) { this->WriteString("<ProjectReference>\n", 2); - this->WriteString( - "<LinkLibraryDependencies>false</LinkLibraryDependencies>\n", 3); + this->WriteElem("LinkLibraryDependencies", "false", 3); this->WriteString("</ProjectReference>\n", 2); } } @@ -3474,6 +3374,17 @@ void cmVisualStudio10TargetGenerator::AddLibraries( std::string currentBinDir = this->LocalGenerator->GetCurrentBinaryDirectory(); for (cmComputeLinkInformation::Item const& l : libs) { + // Do not allow C# targets to be added to the LIB listing. LIB files are + // used for linking C++ dependencies. C# libraries do not have lib files. + // Instead, they compile down to C# reference libraries (DLL files). The + // `<ProjectReference>` elements added to the vcxproj are enough for the + // IDE to deduce the DLL file required by other C# projects that need its + // reference library. + if (l.Target && + cmGlobalVisualStudioGenerator::TargetIsCSharpOnly(l.Target)) { + continue; + } + if (l.IsPath) { std::string path = this->LocalGenerator->ConvertToRelativePath(currentBinDir, l.Value); @@ -3543,15 +3454,11 @@ void cmVisualStudio10TargetGenerator::WriteMidlOptions( this->WriteString("%(AdditionalIncludeDirectories)" "</AdditionalIncludeDirectories>\n", 0); - this->WriteString("<OutputDirectory>$(ProjectDir)/$(IntDir)" - "</OutputDirectory>\n", - 3); - this->WriteString("<HeaderFileName>%(Filename).h</HeaderFileName>\n", 3); - this->WriteString("<TypeLibraryName>%(Filename).tlb</TypeLibraryName>\n", 3); - this->WriteString("<InterfaceIdentifierFileName>" - "%(Filename)_i.c</InterfaceIdentifierFileName>\n", - 3); - this->WriteString("<ProxyFileName>%(Filename)_p.c</ProxyFileName>\n", 3); + this->WriteElem("OutputDirectory", "$(ProjectDir)/$(IntDir)", 3); + this->WriteElem("HeaderFileName", "%(Filename).h", 3); + this->WriteElem("TypeLibraryName", "%(Filename).tlb", 3); + this->WriteElem("InterfaceIdentifierFileName", "%(Filename)_i.c", 3); + this->WriteElem("ProxyFileName", "%(Filename)_p.c", 3); this->WriteString("</Midl>\n", 2); } @@ -3643,8 +3550,7 @@ void cmVisualStudio10TargetGenerator::WriteEvent( } comment = cmVS10EscapeComment(comment); if (this->ProjectType != csproj) { - this->WriteString("<Message>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(comment) << "</Message>\n"; + this->WriteElemEscapeXML("Message", comment, 3); this->WriteString("<Command>", 3); } else { std::string strippedComment = comment; @@ -3679,8 +3585,7 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences() } // skip fortran targets as they can not be processed by MSBuild // the only reference will be in the .sln file - if (static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator) - ->TargetIsFortranOnly(dt)) { + if (this->GlobalGenerator->TargetIsFortranOnly(dt)) { continue; } this->WriteString("<ProjectReference Include=\"", 2); @@ -3698,18 +3603,13 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences() } ConvertToWindowsSlash(path); (*this->BuildFileStream) << cmVS10EscapeXML(path) << "\">\n"; - this->WriteString("<Project>", 3); - (*this->BuildFileStream) << "{" << this->GlobalGenerator->GetGUID(name) - << "}"; - (*this->BuildFileStream) << "</Project>\n"; - this->WriteString("<Name>", 3); - (*this->BuildFileStream) << name << "</Name>\n"; + this->WriteElem("Project", + "{" + this->GlobalGenerator->GetGUID(name) + "}", 3); + this->WriteElem("Name", name, 3); this->WriteDotNetReferenceCustomTags(name); if (csproj == this->ProjectType) { - if (!static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator) - ->TargetCanBeReferenced(dt)) { - this->WriteString( - "<ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n", 3); + if (!this->GlobalGenerator->TargetCanBeReferenced(dt)) { + this->WriteElem("ReferenceOutputAssembly", "false", 3); } } this->WriteString("</ProjectReference>\n", 2); @@ -3839,14 +3739,12 @@ void cmVisualStudio10TargetGenerator::WriteWinRTPackageCertificateKeyFile() this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); ConvertToWindowsSlash(artifactDir); this->WriteString("<PropertyGroup>\n", 1); - this->WriteString("<AppxPackageArtifactsDir>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(artifactDir) - << "\\</AppxPackageArtifactsDir>\n"; - this->WriteString("<ProjectPriFullPath>", 2); + this->WriteElemEscapeXML("AppxPackageArtifactsDir", artifactDir + "\\", + 2); std::string resourcePriFile = this->DefaultArtifactDir + "/resources.pri"; ConvertToWindowsSlash(resourcePriFile); - (*this->BuildFileStream) << resourcePriFile << "</ProjectPriFullPath>\n"; + this->WriteElem("ProjectPriFullPath", resourcePriFile, 2); // If we are missing files and we don't have a certificate and // aren't targeting WP8.0, add a default certificate @@ -3860,26 +3758,18 @@ void cmVisualStudio10TargetGenerator::WriteWinRTPackageCertificateKeyFile() this->AddedFiles.push_back(pfxFile); } - this->WriteString("<", 2); - (*this->BuildFileStream) << "PackageCertificateKeyFile>" << pfxFile - << "</PackageCertificateKeyFile>\n"; + this->WriteElem("PackageCertificateKeyFile", pfxFile, 2); std::string thumb = cmSystemTools::ComputeCertificateThumbprint(pfxFile); if (!thumb.empty()) { - this->WriteString("<PackageCertificateThumbprint>", 2); - (*this->BuildFileStream) << thumb - << "</PackageCertificateThumbprint>\n"; + this->WriteElem("PackageCertificateThumbprint", thumb, 2); } this->WriteString("</PropertyGroup>\n", 1); } else if (!pfxFile.empty()) { this->WriteString("<PropertyGroup>\n", 1); - this->WriteString("<", 2); - (*this->BuildFileStream) << "PackageCertificateKeyFile>" << pfxFile - << "</PackageCertificateKeyFile>\n"; + this->WriteElem("PackageCertificateKeyFile", pfxFile, 2); std::string thumb = cmSystemTools::ComputeCertificateThumbprint(pfxFile); if (!thumb.empty()) { - this->WriteString("<PackageCertificateThumbprint>", 2); - (*this->BuildFileStream) << thumb - << "</PackageCertificateThumbprint>\n"; + this->WriteElem("PackageCertificateThumbprint", thumb, 2); } this->WriteString("</PropertyGroup>\n", 1); } @@ -3921,52 +3811,35 @@ bool cmVisualStudio10TargetGenerator::IsXamlSource( void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings() { - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; bool isAppContainer = false; bool const isWindowsPhone = this->GlobalGenerator->TargetsWindowsPhone(); bool const isWindowsStore = this->GlobalGenerator->TargetsWindowsStore(); std::string const& v = this->GlobalGenerator->GetSystemVersion(); if (isWindowsPhone || isWindowsStore) { - this->WriteString("<ApplicationType>", 2); - (*this->BuildFileStream) - << (isWindowsPhone ? "Windows Phone" : "Windows Store") - << "</ApplicationType>\n"; - this->WriteString("<DefaultLanguage>en-US" - "</DefaultLanguage>\n", - 2); + this->WriteElem("ApplicationType", + (isWindowsPhone ? "Windows Phone" : "Windows Store"), 2); + this->WriteElem("DefaultLanguage", "en-US", 2); if (cmHasLiteralPrefix(v, "10.0")) { - this->WriteString("<ApplicationTypeRevision>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML("10.0") - << "</ApplicationTypeRevision>\n"; + this->WriteElemEscapeXML("ApplicationTypeRevision", "10.0", 2); // Visual Studio 14.0 is necessary for building 10.0 apps - this->WriteString("<MinimumVisualStudioVersion>14.0" - "</MinimumVisualStudioVersion>\n", - 2); + this->WriteElem("MinimumVisualStudioVersion", "14.0", 2); if (this->GeneratorTarget->GetType() < cmStateEnums::UTILITY) { isAppContainer = true; } } else if (v == "8.1") { - this->WriteString("<ApplicationTypeRevision>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(v) - << "</ApplicationTypeRevision>\n"; + this->WriteElemEscapeXML("ApplicationTypeRevision", v, 2); // Visual Studio 12.0 is necessary for building 8.1 apps - this->WriteString("<MinimumVisualStudioVersion>12.0" - "</MinimumVisualStudioVersion>\n", - 2); + this->WriteElem("MinimumVisualStudioVersion", "12.0", 2); if (this->GeneratorTarget->GetType() < cmStateEnums::UTILITY) { isAppContainer = true; } } else if (v == "8.0") { - this->WriteString("<ApplicationTypeRevision>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(v) - << "</ApplicationTypeRevision>\n"; + this->WriteElemEscapeXML("ApplicationTypeRevision", v, 2); // Visual Studio 11.0 is necessary for building 8.0 apps - this->WriteString("<MinimumVisualStudioVersion>11.0" - "</MinimumVisualStudioVersion>\n", - 2); + this->WriteElem("MinimumVisualStudioVersion", "11.0", 2); if (isWindowsStore && this->GeneratorTarget->GetType() < cmStateEnums::UTILITY) { @@ -3974,52 +3847,42 @@ void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings() } else if (isWindowsPhone && this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) { - this->WriteString("<XapOutputs>true</XapOutputs>\n", 2); - this->WriteString("<XapFilename>", 2); - (*this->BuildFileStream) - << cmVS10EscapeXML(this->Name) - << "_$(Configuration)_$(Platform).xap</XapFilename>\n"; + this->WriteElem("XapOutputs", "true", 2); + this->WriteElem("XapFilename", cmVS10EscapeXML(this->Name) + + "_$(Configuration)_$(Platform).xap", + 2); } } } if (isAppContainer) { - this->WriteString("<AppContainerApplication>true" - "</AppContainerApplication>\n", - 2); + this->WriteElem("AppContainerApplication", "true", 2); } else if (this->Platform == "ARM64") { - this->WriteString("<WindowsSDKDesktopARM64Support>true" - "</WindowsSDKDesktopARM64Support>\n", - 2); + this->WriteElem("WindowsSDKDesktopARM64Support", "true", 2); } else if (this->Platform == "ARM") { - this->WriteString("<WindowsSDKDesktopARMSupport>true" - "</WindowsSDKDesktopARMSupport>\n", - 2); + this->WriteElem("WindowsSDKDesktopARMSupport", "true", 2); } std::string const& targetPlatformVersion = gg->GetWindowsTargetPlatformVersion(); if (!targetPlatformVersion.empty()) { - this->WriteString("<WindowsTargetPlatformVersion>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(targetPlatformVersion) - << "</WindowsTargetPlatformVersion>\n"; + this->WriteElemEscapeXML("WindowsTargetPlatformVersion", + targetPlatformVersion, 2); } const char* targetPlatformMinVersion = this->GeneratorTarget->GetProperty( "VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION"); if (targetPlatformMinVersion) { - this->WriteString("<WindowsTargetPlatformMinVersion>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(targetPlatformMinVersion) - << "</WindowsTargetPlatformMinVersion>\n"; + this->WriteElemEscapeXML("WindowsTargetPlatformMinVersion", + targetPlatformMinVersion, 2); } else if (isWindowsStore && cmHasLiteralPrefix(v, "10.0")) { // If the min version is not set, then use the TargetPlatformVersion if (!targetPlatformVersion.empty()) { - this->WriteString("<WindowsTargetPlatformMinVersion>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(targetPlatformVersion) - << "</WindowsTargetPlatformMinVersion>\n"; + this->WriteElemEscapeXML("WindowsTargetPlatformMinVersion", + targetPlatformVersion, 2); } } // Added IoT Startup Task support if (this->GeneratorTarget->GetPropertyAsBool("VS_IOT_STARTUP_TASK")) { - this->WriteString("<ContainsStartupTask>true</ContainsStartupTask>\n", 2); + this->WriteElem("ContainsStartupTask", "true", 2); } } @@ -4150,7 +4013,7 @@ void cmVisualStudio10TargetGenerator::WriteMissingFilesWP80() ConvertToWindowsSlash(sourceFile); this->WriteString("<Xml Include=\"", 2); (*this->BuildFileStream) << cmVS10EscapeXML(sourceFile) << "\">\n"; - this->WriteString("<SubType>Designer</SubType>\n", 3); + this->WriteElem("SubType", "Designer", 3); this->WriteString("</Xml>\n", 2); this->AddedFiles.push_back(sourceFile); @@ -4428,7 +4291,7 @@ void cmVisualStudio10TargetGenerator::WriteCommonMissingFiles( ConvertToWindowsSlash(sourceFile); this->WriteString("<AppxManifest Include=\"", 2); (*this->BuildFileStream) << cmVS10EscapeXML(sourceFile) << "\">\n"; - this->WriteString("<SubType>Designer</SubType>\n", 3); + this->WriteElem("SubType", "Designer", 3); this->WriteString("</AppxManifest>\n", 2); this->AddedFiles.push_back(sourceFile); diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index 33d4fb7..7106737 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -21,7 +21,7 @@ class cmLocalVisualStudio7Generator; class cmMakefile; class cmSourceFile; class cmSourceGroup; -class cmVisualStudioGeneratorOptions; +class cmVS10GeneratorOptions; class cmVisualStudio10TargetGenerator { @@ -34,8 +34,7 @@ public: void Generate(); // used by cmVisualStudioGeneratorOptions void WritePlatformConfigTag(const char* tag, const std::string& config, - int indentLevel, const char* attribute = 0, - const char* end = 0, std::ostream* strm = 0); + int indentLevel, const char* attribute = 0); private: struct ToolSource @@ -53,8 +52,14 @@ private: std::vector<std::string> Configs; }; + struct Elem; + std::string ConvertPath(std::string const& path, bool forceRelative); void WriteString(const char* line, int indentLevel); + void WriteElem(const char* tag, const char* val, int indentLevel); + void WriteElem(const char* tag, std::string const& val, int indentLevel); + void WriteElemEscapeXML(const char* tag, std::string const& val, + int indentLevel); void WriteProjectConfigurations(); void WriteProjectConfigurationValues(); void WriteMSToolConfigurationValues(std::string const& config); @@ -62,9 +67,9 @@ private: void WriteHeaderSource(cmSourceFile const* sf); void WriteExtraSource(cmSourceFile const* sf); void WriteNsightTegraConfigurationValues(std::string const& config); - void WriteSource(std::string const& tool, cmSourceFile const* sf, - const char* end = 0); - void WriteExcludeFromBuild(std::vector<size_t> const& exclude_configs); + void WriteSource(std::string const& tool, cmSourceFile const* sf); + void WriteExcludeFromBuild(Elem&, + std::vector<size_t> const& exclude_configs); void WriteAllSources(); void WriteDotNetReferences(); void WriteDotNetReference(std::string const& ref, std::string const& hint); @@ -141,7 +146,7 @@ private: void WriteGroups(); void WriteProjectReferences(); void WriteApplicationTypeSettings(); - bool OutputSourceSpecificFlags(cmSourceFile const* source); + void OutputSourceSpecificFlags(Elem&, cmSourceFile const* source); void AddLibraries(cmComputeLinkInformation& cli, std::vector<std::string>& libVec, std::vector<std::string>& vsTargetVec); @@ -153,7 +158,7 @@ private: void WriteEvent(const char* name, std::vector<cmCustomCommand> const& commands, std::string const& configName); - void WriteGroupSources(const char* name, ToolSources const& sources, + void WriteGroupSources(std::string const& name, ToolSources const& sources, std::vector<cmSourceGroup>&); void AddMissingSourceGroups(std::set<cmSourceGroup*>& groupsUsed, const std::vector<cmSourceGroup>& allGroups); @@ -170,7 +175,7 @@ private: void GetCSharpSourceLink(cmSourceFile const* sf, std::string& link); private: - typedef cmVisualStudioGeneratorOptions Options; + typedef cmVS10GeneratorOptions Options; typedef std::map<std::string, std::unique_ptr<Options>> OptionsMap; OptionsMap ClOptions; OptionsMap RcOptions; @@ -190,19 +195,19 @@ private: bool InSourceBuild; std::vector<std::string> Configurations; std::vector<TargetsFileAndConfigs> TargetsFileAndConfigsVec; - cmGeneratorTarget* GeneratorTarget; - cmMakefile* Makefile; - std::string Platform; - std::string GUID; - std::string Name; + cmGeneratorTarget* const GeneratorTarget; + cmMakefile* const Makefile; + std::string const Platform; + std::string const Name; + std::string const GUID; bool MSTools; bool Managed; bool NsightTegra; int NsightTegraVersion[4]; bool TargetCompileAsWinRT; - cmGlobalVisualStudio10Generator* GlobalGenerator; + cmGlobalVisualStudio10Generator* const GlobalGenerator; cmGeneratedFileStream* BuildFileStream; - cmLocalVisualStudio7Generator* LocalGenerator; + cmLocalVisualStudio7Generator* const LocalGenerator; std::set<cmSourceFile const*> SourcesVisited; std::set<std::string> CSharpCustomCommandNames; bool IsMissingFiles; diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx index ccbff83..8b6f057 100644 --- a/Source/cmVisualStudioGeneratorOptions.cxx +++ b/Source/cmVisualStudioGeneratorOptions.cxx @@ -4,43 +4,19 @@ #include "cmLocalVisualStudioGenerator.h" #include "cmOutputConverter.h" #include "cmSystemTools.h" -#include "cmVisualStudio10TargetGenerator.h" -static std::string cmVisualStudio10GeneratorOptionsEscapeForXML( - std::string ret) +static void cmVS10EscapeForMSBuild(std::string& ret) { cmSystemTools::ReplaceString(ret, ";", "%3B"); - cmSystemTools::ReplaceString(ret, "&", "&"); - cmSystemTools::ReplaceString(ret, "<", "<"); - cmSystemTools::ReplaceString(ret, ">", ">"); - return ret; -} - -static std::string cmVisualStudioGeneratorOptionsEscapeForXML(std::string ret) -{ - cmSystemTools::ReplaceString(ret, "&", "&"); - cmSystemTools::ReplaceString(ret, "\"", """); - cmSystemTools::ReplaceString(ret, "<", "<"); - cmSystemTools::ReplaceString(ret, ">", ">"); - cmSystemTools::ReplaceString(ret, "\n", "
"); - return ret; -} - -cmVisualStudioGeneratorOptions::cmVisualStudioGeneratorOptions( - cmLocalVisualStudioGenerator* lg, Tool tool, - cmVisualStudio10TargetGenerator* g) - : cmVisualStudioGeneratorOptions(lg, tool, nullptr, nullptr, g) -{ } cmVisualStudioGeneratorOptions::cmVisualStudioGeneratorOptions( cmLocalVisualStudioGenerator* lg, Tool tool, cmVS7FlagTable const* table, - cmVS7FlagTable const* extraTable, cmVisualStudio10TargetGenerator* g) + cmVS7FlagTable const* extraTable) : cmIDEOptions() , LocalGenerator(lg) , Version(lg->GetVersion()) , CurrentTool(tool) - , TargetGenerator(g) { // Store the given flag tables. this->AddTable(table); @@ -152,9 +128,8 @@ bool cmVisualStudioGeneratorOptions::IsManaged() const bool cmVisualStudioGeneratorOptions::UsingUnicode() const { // Look for the a _UNICODE definition. - for (std::vector<std::string>::const_iterator di = this->Defines.begin(); - di != this->Defines.end(); ++di) { - if (*di == "_UNICODE") { + for (std::string const& di : this->Defines) { + if (di == "_UNICODE") { return true; } } @@ -163,9 +138,8 @@ bool cmVisualStudioGeneratorOptions::UsingUnicode() const bool cmVisualStudioGeneratorOptions::UsingSBCS() const { // Look for the a _SBCS definition. - for (std::vector<std::string>::const_iterator di = this->Defines.begin(); - di != this->Defines.end(); ++di) { - if (*di == "_SBCS") { + for (std::string const& di : this->Defines) { + if (di == "_SBCS") { return true; } } @@ -227,7 +201,7 @@ void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration() // It translates to -arch=<virtual> -code=<real>. cmSystemTools::ReplaceString(arch_name, "sm_", "compute_"); } - for (auto const& c : codes) { + for (std::string const& c : codes) { std::string entry = arch_name + "," + c; result.push_back(entry); } @@ -237,7 +211,7 @@ void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration() // -gencode=<arch>,<code> // -gencode=<arch>,[<code1>,<code2>] // -gencode=<arch>,"<code1>,<code2>" - for (auto const& e : gencode) { + for (std::string const& e : gencode) { std::string entry = e; cmSystemTools::ReplaceString(entry, "arch=", ""); cmSystemTools::ReplaceString(entry, "code=", ""); @@ -285,7 +259,7 @@ void cmVisualStudioGeneratorOptions::FixManifestUACFlags() uacExecuteLevelMap["highestAvailable"] = "HighestAvailable"; uacExecuteLevelMap["requireAdministrator"] = "RequireAdministrator"; - for (auto const& subopt : subOptions) { + for (std::string const& subopt : subOptions) { std::vector<std::string> keyValue; cmsys::SystemTools::Split(subopt, keyValue, '='); if (keyValue.size() != 2 || (uacMap.find(keyValue[0]) == uacMap.end())) { @@ -332,9 +306,8 @@ void cmVisualStudioGeneratorOptions::Parse(const char* flags) // Process flags that need to be represented specially in the IDE // project file. - for (std::vector<std::string>::iterator ai = args.begin(); ai != args.end(); - ++ai) { - this->HandleFlag(ai->c_str()); + for (std::string const& ai : args) { + this->HandleFlag(ai); } } @@ -396,23 +369,23 @@ void cmVisualStudioGeneratorOptions::Reparse(std::string const& key) this->Parse(original.c_str()); } -void cmVisualStudioGeneratorOptions::StoreUnknownFlag(const char* flag) +void cmVisualStudioGeneratorOptions::StoreUnknownFlag(std::string const& flag) { // Look for Intel Fortran flags that do not map well in the flag table. if (this->CurrentTool == FortranCompiler) { - if (strcmp(flag, "/dbglibs") == 0) { + if (flag == "/dbglibs") { this->FortranRuntimeDebug = true; return; } - if (strcmp(flag, "/threads") == 0) { + if (flag == "/threads") { this->FortranRuntimeMT = true; return; } - if (strcmp(flag, "/libs:dll") == 0) { + if (flag == "/libs:dll") { this->FortranRuntimeDLL = true; return; } - if (strcmp(flag, "/libs:static") == 0) { + if (flag == "/libs:static") { this->FortranRuntimeDLL = false; return; } @@ -420,7 +393,7 @@ void cmVisualStudioGeneratorOptions::StoreUnknownFlag(const char* flag) // This option is not known. Store it in the output flags. std::string const opts = cmOutputConverter::EscapeWindowsShellArgument( - flag, cmOutputConverter::Shell_Flag_AllowMakeVariables | + flag.c_str(), cmOutputConverter::Shell_Flag_AllowMakeVariables | cmOutputConverter::Shell_Flag_VSIDE); this->AppendFlagString(this->UnknownFlagField, opts); } @@ -437,14 +410,19 @@ cmIDEOptions::FlagValue cmVisualStudioGeneratorOptions::TakeFlag( return value; } -void cmVisualStudioGeneratorOptions::SetConfiguration(const char* config) +void cmVisualStudioGeneratorOptions::SetConfiguration( + const std::string& config) { this->Configuration = config; } +const std::string& cmVisualStudioGeneratorOptions::GetConfiguration() const +{ + return this->Configuration; +} + void cmVisualStudioGeneratorOptions::OutputPreprocessorDefinitions( - std::ostream& fout, const char* prefix, const char* suffix, - const std::string& lang) + std::ostream& fout, const char* prefix, const std::string& lang) { if (this->Defines.empty()) { return; @@ -453,19 +431,8 @@ void cmVisualStudioGeneratorOptions::OutputPreprocessorDefinitions( if (lang == "CUDA") { tag = "Defines"; } - 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 << "=\""; - } + + std::ostringstream oss; const char* sep = ""; std::vector<std::string>::const_iterator de = cmRemoveDuplicates(this->Defines); @@ -474,34 +441,30 @@ void cmVisualStudioGeneratorOptions::OutputPreprocessorDefinitions( // Escape the definition for the compiler. std::string define; if (this->Version < cmGlobalVisualStudioGenerator::VS10) { - define = this->LocalGenerator->EscapeForShell(di->c_str(), true); + define = this->LocalGenerator->EscapeForShell(*di, true); } else { define = *di; } - // Escape this flag for the IDE. + // Escape this flag for the MSBuild. if (this->Version >= cmGlobalVisualStudioGenerator::VS10) { - define = cmVisualStudio10GeneratorOptionsEscapeForXML(define); - + cmVS10EscapeForMSBuild(define); if (lang == "RC") { cmSystemTools::ReplaceString(define, "\"", "\\\""); } - } else { - define = cmVisualStudioGeneratorOptionsEscapeForXML(define); } // Store the flag in the project file. - fout << sep << define; + oss << sep << define; sep = ";"; } if (this->Version >= cmGlobalVisualStudioGenerator::VS10) { - fout << ";%(" << tag << ")</" << tag << ">" << suffix; - } else { - fout << "\"" << suffix; + oss << ";%(" << tag << ")"; } + + this->OutputFlag(fout, prefix, tag, oss.str()); } void cmVisualStudioGeneratorOptions::OutputAdditionalIncludeDirectories( - std::ostream& fout, const char* prefix, const char* suffix, - const std::string& lang) + std::ostream& fout, const char* prefix, const std::string& lang) { if (this->Includes.empty()) { return; @@ -514,20 +477,7 @@ void cmVisualStudioGeneratorOptions::OutputAdditionalIncludeDirectories( 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 << "=\""; - } - + std::ostringstream oss; const char* sep = ""; for (std::string include : this->Includes) { // first convert all of the slashes @@ -541,59 +491,40 @@ void cmVisualStudioGeneratorOptions::OutputAdditionalIncludeDirectories( include += "\\"; } - // Escape this include for the IDE. - fout << sep << (this->Version >= cmGlobalVisualStudioGenerator::VS10 - ? cmVisualStudio10GeneratorOptionsEscapeForXML(include) - : cmVisualStudioGeneratorOptionsEscapeForXML(include)); + // Escape this include for the MSBuild. + if (this->Version >= cmGlobalVisualStudioGenerator::VS10) { + cmVS10EscapeForMSBuild(include); + } + oss << sep << include; sep = ";"; if (lang == "Fortran") { include += "/$(ConfigurationName)"; - fout << sep << (this->Version >= cmGlobalVisualStudioGenerator::VS10 - ? cmVisualStudio10GeneratorOptionsEscapeForXML(include) - : cmVisualStudioGeneratorOptionsEscapeForXML(include)); + oss << sep << include; } } if (this->Version >= cmGlobalVisualStudioGenerator::VS10) { - fout << sep << "%(" << tag << ")</" << tag << ">" << suffix; - } else { - fout << "\"" << suffix; + oss << sep << "%(" << tag << ")"; } + + this->OutputFlag(fout, prefix, tag, oss.str()); } void cmVisualStudioGeneratorOptions::OutputFlagMap(std::ostream& fout, const char* indent) { - if (this->Version >= cmGlobalVisualStudioGenerator::VS10) { - for (std::map<std::string, FlagValue>::iterator m = this->FlagMap.begin(); - m != this->FlagMap.end(); ++m) { - fout << indent; - if (!this->Configuration.empty()) { - this->TargetGenerator->WritePlatformConfigTag( - m->first.c_str(), this->Configuration.c_str(), 0, 0, 0, &fout); - } else { - fout << "<" << m->first << ">"; + for (auto const& m : this->FlagMap) { + std::ostringstream oss; + const char* sep = ""; + for (std::string i : m.second) { + if (this->Version >= cmGlobalVisualStudioGenerator::VS10) { + cmVS10EscapeForMSBuild(i); } - const char* sep = ""; - for (std::vector<std::string>::iterator i = m->second.begin(); - i != m->second.end(); ++i) { - fout << sep << cmVisualStudio10GeneratorOptionsEscapeForXML(*i); - sep = ";"; - } - fout << "</" << m->first << ">\n"; - } - } else { - for (std::map<std::string, FlagValue>::iterator m = this->FlagMap.begin(); - m != this->FlagMap.end(); ++m) { - fout << indent << m->first << "=\""; - const char* sep = ""; - for (std::vector<std::string>::iterator i = m->second.begin(); - i != m->second.end(); ++i) { - fout << sep << cmVisualStudioGeneratorOptionsEscapeForXML(*i); - sep = ";"; - } - fout << "\"\n"; + oss << sep << i; + sep = ";"; } + + this->OutputFlag(fout, indent, m.first.c_str(), oss.str()); } } diff --git a/Source/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h index 2dffe9b..974ca62 100644 --- a/Source/cmVisualStudioGeneratorOptions.h +++ b/Source/cmVisualStudioGeneratorOptions.h @@ -16,8 +16,6 @@ class cmLocalVisualStudioGenerator; typedef cmIDEFlagTable cmVS7FlagTable; -class cmVisualStudio10TargetGenerator; - class cmVisualStudioGeneratorOptions : public cmIDEOptions { public: @@ -34,12 +32,8 @@ public: CSharpCompiler }; cmVisualStudioGeneratorOptions(cmLocalVisualStudioGenerator* lg, Tool tool, - cmVS7FlagTable const* table, - cmVS7FlagTable const* extraTable = 0, - cmVisualStudio10TargetGenerator* g = 0); - - cmVisualStudioGeneratorOptions(cmLocalVisualStudioGenerator* lg, Tool tool, - cmVisualStudio10TargetGenerator* g = 0); + cmVS7FlagTable const* table = nullptr, + cmVS7FlagTable const* extraTable = nullptr); // Add a table of flags. void AddTable(cmVS7FlagTable const* table); @@ -84,14 +78,17 @@ public: bool IsManaged() const; // Write options to output. 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); + void SetConfiguration(const std::string& config); + const std::string& GetConfiguration() const; + +protected: + virtual void OutputFlag(std::ostream& fout, const char* indent, + const char* tag, const std::string& content) = 0; private: cmLocalVisualStudioGenerator* LocalGenerator; @@ -99,7 +96,6 @@ private: std::string Configuration; Tool CurrentTool; - cmVisualStudio10TargetGenerator* TargetGenerator; bool FortranRuntimeDebug; bool FortranRuntimeDLL; @@ -107,7 +103,7 @@ private: std::string UnknownFlagField; - virtual void StoreUnknownFlag(const char* flag); + void StoreUnknownFlag(std::string const& flag) override; FlagValue TakeFlag(std::string const& key); }; diff --git a/Source/cmWorkingDirectory.cxx b/Source/cmWorkingDirectory.cxx index 99c9ba8..816f104 100644 --- a/Source/cmWorkingDirectory.cxx +++ b/Source/cmWorkingDirectory.cxx @@ -4,10 +4,12 @@ #include "cmSystemTools.h" +#include <cerrno> + cmWorkingDirectory::cmWorkingDirectory(std::string const& newdir) { this->OldDir = cmSystemTools::GetCurrentWorkingDirectory(); - cmSystemTools::ChangeDirectory(newdir); + this->SetDirectory(newdir); } cmWorkingDirectory::~cmWorkingDirectory() @@ -15,10 +17,20 @@ cmWorkingDirectory::~cmWorkingDirectory() this->Pop(); } +bool cmWorkingDirectory::SetDirectory(std::string const& newdir) +{ + if (cmSystemTools::ChangeDirectory(newdir) == 0) { + this->ResultCode = 0; + return true; + } + this->ResultCode = errno; + return false; +} + void cmWorkingDirectory::Pop() { if (!this->OldDir.empty()) { - cmSystemTools::ChangeDirectory(this->OldDir); + this->SetDirectory(this->OldDir); this->OldDir.clear(); } } diff --git a/Source/cmWorkingDirectory.h b/Source/cmWorkingDirectory.h index aff9267..1f18ce7 100644 --- a/Source/cmWorkingDirectory.h +++ b/Source/cmWorkingDirectory.h @@ -9,6 +9,12 @@ /** \class cmWorkingDirectory * \brief An RAII class to manipulate the working directory. + * + * The current working directory is set to the location given to the + * constructor. The working directory can be changed again as needed + * by calling SetDirectory(). When the object is destroyed, the destructor + * will restore the working directory to what it was when the object was + * created, regardless of any calls to SetDirectory() in the meantime. */ class cmWorkingDirectory { @@ -16,10 +22,21 @@ public: cmWorkingDirectory(std::string const& newdir); ~cmWorkingDirectory(); + bool SetDirectory(std::string const& newdir); void Pop(); + bool Failed() const { return ResultCode != 0; } + + /** \return 0 if the last attempt to set the working directory was + * successful. If it failed, the value returned will be the + * \c errno value associated with the failure. A description + * of the error code can be obtained by passing the result + * to \c std::strerror(). + */ + int GetLastResult() const { return ResultCode; } private: std::string OldDir; + int ResultCode; }; #endif diff --git a/Source/cmXMLWriter.h b/Source/cmXMLWriter.h index 7bae21e..80940ee 100644 --- a/Source/cmXMLWriter.h +++ b/Source/cmXMLWriter.h @@ -133,4 +133,56 @@ private: bool IsContent; }; +class cmXMLElement; // IWYU pragma: keep + +class cmXMLDocument +{ +public: + cmXMLDocument(cmXMLWriter& xml) + : xmlwr(xml) + { + xmlwr.StartDocument(); + } + ~cmXMLDocument() { xmlwr.EndDocument(); } +private: + friend class cmXMLElement; + cmXMLWriter& xmlwr; +}; + +class cmXMLElement +{ +public: + cmXMLElement(cmXMLWriter& xml, const char* tag) + : xmlwr(xml) + { + xmlwr.StartElement(tag); + } + cmXMLElement(cmXMLElement& par, const char* tag) + : xmlwr(par.xmlwr) + { + xmlwr.StartElement(tag); + } + cmXMLElement(cmXMLDocument& doc, const char* tag) + : xmlwr(doc.xmlwr) + { + xmlwr.StartElement(tag); + } + ~cmXMLElement() { xmlwr.EndElement(); } + + template <typename T> + cmXMLElement& Attribute(const char* name, T const& value) + { + xmlwr.Attribute(name, value); + return *this; + } + template <typename T> + void Content(T const& content) + { + xmlwr.Content(content); + } + +private: + cmXMLWriter& xmlwr; +}; + #endif diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 5620723..83c5384 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -55,7 +55,6 @@ #include "cmGlobalVisualStudio12Generator.h" #include "cmGlobalVisualStudio14Generator.h" #include "cmGlobalVisualStudio15Generator.h" -#include "cmGlobalVisualStudio8Generator.h" #include "cmGlobalVisualStudio9Generator.h" #include "cmVSSetupHelper.h" @@ -98,13 +97,13 @@ #include "cmsys/Glob.hxx" #include "cmsys/RegularExpression.hxx" #include <algorithm> +#include <cstring> #include <iostream> #include <iterator> #include <memory> // IWYU pragma: keep #include <sstream> #include <stdio.h> #include <stdlib.h> -#include <string.h> #include <utility> namespace { @@ -1464,8 +1463,7 @@ void cmake::CreateDefaultGlobalGenerator() { "12.0", "Visual Studio 12 2013" }, // { "11.0", "Visual Studio 11 2012" }, // { "10.0", "Visual Studio 10 2010" }, // - { "9.0", "Visual Studio 9 2008" }, // - { "8.0", "Visual Studio 8 2005" } + { "9.0", "Visual Studio 9 2008" } }; static const char* const vsEntries[] = { "\\Setup\\VC;ProductDir", // @@ -1689,7 +1687,6 @@ void cmake::AddDefaultGenerators() this->Generators.push_back(cmGlobalVisualStudio11Generator::NewFactory()); this->Generators.push_back(cmGlobalVisualStudio10Generator::NewFactory()); this->Generators.push_back(cmGlobalVisualStudio9Generator::NewFactory()); - this->Generators.push_back(cmGlobalVisualStudio8Generator::NewFactory()); this->Generators.push_back(cmGlobalBorlandMakefileGenerator::NewFactory()); this->Generators.push_back(cmGlobalNMakeMakefileGenerator::NewFactory()); this->Generators.push_back(cmGlobalJOMMakefileGenerator::NewFactory()); @@ -2209,6 +2206,15 @@ int cmake::GetSystemInformation(std::vector<std::string>& args) { // now run cmake on the CMakeLists file cmWorkingDirectory workdir(destPath); + if (workdir.Failed()) { + // We created the directory and we were able to copy the CMakeLists.txt + // file to it, so we wouldn't expect to get here unless the default + // permissions are questionable or some other process has deleted the + // directory + std::cerr << "Failed to change to directory " << destPath << " : " + << std::strerror(workdir.GetLastResult()) << std::endl; + return 1; + } std::vector<std::string> args2; args2.push_back(args[0]); args2.push_back(destPath); @@ -2387,17 +2393,17 @@ int cmake::Build(const std::string& dir, const std::string& target, std::cerr << "Error: could not find CMAKE_GENERATOR in Cache\n"; return 1; } - std::unique_ptr<cmGlobalGenerator> gen( - this->CreateGlobalGenerator(cachedGenerator)); - if (!gen.get()) { + cmGlobalGenerator* gen = this->CreateGlobalGenerator(cachedGenerator); + if (!gen) { std::cerr << "Error: could create CMAKE_GENERATOR \"" << cachedGenerator << "\"\n"; return 1; } + this->SetGlobalGenerator(gen); const char* cachedGeneratorInstance = this->State->GetCacheEntryValue("CMAKE_GENERATOR_INSTANCE"); if (cachedGeneratorInstance) { - cmMakefile mf(gen.get(), this->GetCurrentSnapshot()); + cmMakefile mf(gen, this->GetCurrentSnapshot()); if (!gen->SetGeneratorInstance(cachedGeneratorInstance, &mf)) { return 1; } @@ -2425,7 +2431,7 @@ int cmake::Build(const std::string& dir, const std::string& target, // to limitations of the underlying build system. std::string const stampList = cachePath + "/" + GetCMakeFilesDirectoryPostSlash() + - cmGlobalVisualStudio8Generator::GetGenerateStampList(); + cmGlobalVisualStudio9Generator::GetGenerateStampList(); // Note that the stampList file only exists for VS generators. if (cmSystemTools::FileExists(stampList) && diff --git a/Source/cmake.h b/Source/cmake.h index 1ac549b..cc56a07 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -574,6 +574,7 @@ private: F(cxx_std_11) \ F(cxx_std_14) \ F(cxx_std_17) \ + F(cxx_std_20) \ F(cxx_aggregate_default_initializers) \ F(cxx_alias_templates) \ F(cxx_alignas) \ diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 0988c3c..6f3a90f 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -359,7 +359,8 @@ struct CoCompileJob int cmcmd::HandleCoCompileCommands(std::vector<std::string>& args) { std::vector<CoCompileJob> jobs; - std::string sourceFile; // store --source= + std::string sourceFile; // store --source= + std::vector<std::string> launchers; // store --launcher= // Default is to run the original command found after -- if the option // does not need to do that, it should be specified here, currently only @@ -390,15 +391,17 @@ int cmcmd::HandleCoCompileCommands(std::vector<std::string>& args) } } } - if (cmHasLiteralPrefix(arg, "--source=")) { - sourceFile = arg.substr(9); - optionFound = true; - } - // if it was not a co-compiler or --source then error if (!optionFound) { - std::cerr << "__run_co_compile given unknown argument: " << arg - << "\n"; - return 1; + if (cmHasLiteralPrefix(arg, "--source=")) { + sourceFile = arg.substr(9); + } else if (cmHasLiteralPrefix(arg, "--launcher=")) { + cmSystemTools::ExpandListArgument(arg.substr(11), launchers, true); + } else { + // if it was not a co-compiler or --source/--launcher then error + std::cerr << "__run_co_compile given unknown argument: " << arg + << "\n"; + return 1; + } } } else { // if not doing_options then push to orig_cmd orig_cmd.push_back(arg); @@ -436,6 +439,11 @@ int cmcmd::HandleCoCompileCommands(std::vector<std::string>& args) return 0; } + // Prepend launcher argument(s), if any + if (!launchers.empty()) { + orig_cmd.insert(orig_cmd.begin(), launchers.begin(), launchers.end()); + } + // Now run the real compiler command and return its result value int ret; if (!cmSystemTools::RunSingleCommand(orig_cmd, nullptr, nullptr, &ret, @@ -689,8 +697,6 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args) // Touch file if (args[1] == "touch_nocreate" && args.size() > 2) { for (std::string::size_type cc = 2; cc < args.size(); cc++) { - // Complain if the file could not be removed, still exists, - // and the -f option was not given. if (!cmSystemTools::Touch(args[cc], false)) { return 1; } diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx index 106afe5..52f509a 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -3344,15 +3344,20 @@ std::string SystemTools::RelativePath(const std::string& local, static std::string GetCasePathName(std::string const& pathIn) { std::string casePath; - std::vector<std::string> path_components; - SystemTools::SplitPath(pathIn, path_components); - if (path_components[0].empty()) // First component always exists. - { - // Relative paths cannot be converted. + + // First check if the file is relative. We don't fix relative paths since the + // real case depends on the root directory and the given path fragment may + // have meaning elsewhere in the project. + if (!SystemTools::FileIsFullPath(pathIn)) { + // This looks unnecessary, but it allows for the return value optimization + // since all return paths return the same local variable. casePath = pathIn; return casePath; } + std::vector<std::string> path_components; + SystemTools::SplitPath(pathIn, path_components); + // Start with root component. std::vector<std::string>::size_type idx = 0; casePath = path_components[idx++]; diff --git a/Source/kwsys/Terminal.c b/Source/kwsys/Terminal.c index eaa5c7d..c9f9dc5 100644 --- a/Source/kwsys/Terminal.c +++ b/Source/kwsys/Terminal.c @@ -153,6 +153,7 @@ static const char* kwsysTerminalVT100Names[] = { "Eterm", "xterm-88color", "xterm-color", "xterm-debian", + "xterm-kitty", "xterm-termite", 0 }; diff --git a/Source/kwsys/testSystemTools.cxx b/Source/kwsys/testSystemTools.cxx index e436a2b..a6d934b 100644 --- a/Source/kwsys/testSystemTools.cxx +++ b/Source/kwsys/testSystemTools.cxx @@ -738,29 +738,29 @@ static bool CheckGetPath() #endif const char* registryPath = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MyApp; MyKey]"; - std::vector<std::string> originalPathes; - originalPathes.push_back(registryPath); + std::vector<std::string> originalPaths; + originalPaths.push_back(registryPath); - std::vector<std::string> expectedPathes; - expectedPathes.push_back(registryPath); + std::vector<std::string> expectedPaths; + expectedPaths.push_back(registryPath); #ifdef _WIN32 - expectedPathes.push_back("C:/Somewhere/something"); - expectedPathes.push_back("D:/Temp"); + expectedPaths.push_back("C:/Somewhere/something"); + expectedPaths.push_back("D:/Temp"); #else - expectedPathes.push_back("/Somewhere/something"); - expectedPathes.push_back("/tmp"); + expectedPaths.push_back("/Somewhere/something"); + expectedPaths.push_back("/tmp"); #endif bool res = true; res &= CheckPutEnv(std::string(envName) + "=" + envValue, envName, envValue); - std::vector<std::string> pathes = originalPathes; - kwsys::SystemTools::GetPath(pathes, envName); + std::vector<std::string> paths = originalPaths; + kwsys::SystemTools::GetPath(paths, envName); - if (pathes != expectedPathes) { - std::cerr << "GetPath(" << StringVectorToString(originalPathes) << ", " - << envName << ") yielded " << StringVectorToString(pathes) - << " instead of " << StringVectorToString(expectedPathes) + if (paths != expectedPaths) { + std::cerr << "GetPath(" << StringVectorToString(originalPaths) << ", " + << envName << ") yielded " << StringVectorToString(paths) + << " instead of " << StringVectorToString(expectedPaths) << std::endl; res = false; } |