summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/CPack/cmCPackNSISGenerator.cxx41
-rw-r--r--Source/CPack/cmCPackNSISGenerator.h5
-rw-r--r--Source/Checks/cm_cxx_auto_ptr.cxx18
-rw-r--r--Source/Checks/cm_cxx_features.cmake1
-rw-r--r--Source/QtDialog/CMakeSetup.cxx2
-rw-r--r--Source/cmCTest.cxx47
-rw-r--r--Source/cmConfigure.cmake.h.in1
-rw-r--r--Source/cmGlobalGenerator.cxx10
-rw-r--r--Source/cmGlobalGenerator.h2
-rw-r--r--Source/cmGlobalNinjaGenerator.cxx506
-rw-r--r--Source/cmGlobalNinjaGenerator.h16
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx9
-rw-r--r--Source/cmNinjaTargetGenerator.cxx341
-rw-r--r--Source/cmNinjaTargetGenerator.h15
-rw-r--r--Source/cmServer.cxx113
-rw-r--r--Source/cmServer.h4
-rw-r--r--Source/cmServerConnection.cxx8
-rw-r--r--Source/cmServerDictionary.h62
-rw-r--r--Source/cmServerProtocol.cxx254
-rw-r--r--Source/cmServerProtocol.h17
-rw-r--r--Source/cmTarget.cxx3
-rw-r--r--Source/cm_auto_ptr.hxx10
-rw-r--r--Source/cmcmd.cxx17
-rw-r--r--Source/kwsys/testConsoleBuf.cxx37
25 files changed, 1399 insertions, 142 deletions
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 27ca0ca..9eb99ea 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 6)
-set(CMake_VERSION_PATCH 20160923)
+set(CMake_VERSION_PATCH 20160927)
#set(CMake_VERSION_RC 1)
diff --git a/Source/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx
index 2db94f1..b49da7f 100644
--- a/Source/CPack/cmCPackNSISGenerator.cxx
+++ b/Source/CPack/cmCPackNSISGenerator.cxx
@@ -71,14 +71,26 @@ int cmCPackNSISGenerator::PackageFiles()
std::ostringstream str;
std::vector<std::string>::const_iterator it;
for (it = files.begin(); it != files.end(); ++it) {
+ std::string outputDir = "$INSTDIR";
std::string fileN =
cmSystemTools::RelativePath(toplevel.c_str(), it->c_str());
if (!this->Components.empty()) {
+ const std::string::size_type pos = fileN.find('/');
+
+ // Use the custom component install directory if we have one
+ if (pos != std::string::npos) {
+ const std::string componentName = fileN.substr(0, pos);
+ outputDir = CustomComponentInstallDirectory(componentName);
+ } else {
+ outputDir = CustomComponentInstallDirectory(fileN);
+ }
+
// Strip off the component part of the path.
- fileN = fileN.substr(fileN.find('/') + 1, std::string::npos);
+ fileN = fileN.substr(pos + 1, std::string::npos);
}
std::replace(fileN.begin(), fileN.end(), '/', '\\');
- str << " Delete \"$INSTDIR\\" << fileN << "\"" << std::endl;
+
+ str << " Delete \"" << outputDir << "\\" << fileN << "\"" << std::endl;
}
cmCPackLogger(cmCPackLog::LOG_DEBUG, "Uninstall Files: " << str.str()
<< std::endl);
@@ -108,7 +120,12 @@ int cmCPackNSISGenerator::PackageFiles()
}
}
std::replace(fileN.begin(), fileN.end(), '/', '\\');
- dstr << " RMDir \"$INSTDIR\\" << fileN << "\"" << std::endl;
+
+ const std::string componentOutputDir =
+ CustomComponentInstallDirectory(componentName);
+
+ dstr << " RMDir \"" << componentOutputDir << "\\" << fileN << "\""
+ << std::endl;
if (!componentName.empty()) {
this->Components[componentName].Directories.push_back(fileN);
}
@@ -650,7 +667,10 @@ std::string cmCPackNSISGenerator::CreateComponentDescription(
}
componentCode += " SectionIn" + out.str() + "\n";
}
- componentCode += " SetOutPath \"$INSTDIR\"\n";
+
+ const std::string componentOutputDir =
+ CustomComponentInstallDirectory(component->Name);
+ componentCode += " SetOutPath \"" + componentOutputDir + "\"\n";
// Create the actual installation commands
if (component->IsDownloaded) {
@@ -796,13 +816,13 @@ std::string cmCPackNSISGenerator::CreateComponentDescription(
++pathIt) {
path = *pathIt;
std::replace(path.begin(), path.end(), '/', '\\');
- macrosOut << " Delete \"$INSTDIR\\" << path << "\"\n";
+ macrosOut << " Delete \"" << componentOutputDir << "\\" << path << "\"\n";
}
for (pathIt = component->Directories.begin();
pathIt != component->Directories.end(); ++pathIt) {
path = *pathIt;
std::replace(path.begin(), path.end(), '/', '\\');
- macrosOut << " RMDir \"$INSTDIR\\" << path << "\"\n";
+ macrosOut << " RMDir \"" << componentOutputDir << "\\" << path << "\"\n";
}
macrosOut << " noremove_" << component->Name << ":\n";
macrosOut << "!macroend\n";
@@ -914,6 +934,15 @@ std::string cmCPackNSISGenerator::CreateComponentGroupDescription(
return code;
}
+std::string cmCPackNSISGenerator::CustomComponentInstallDirectory(
+ const std::string& componentName)
+{
+ const char* outputDir =
+ this->GetOption("CPACK_NSIS_" + componentName + "_INSTALL_DIRECTORY");
+ const std::string componentOutputDir = (outputDir ? outputDir : "$INSTDIR");
+ return componentOutputDir;
+}
+
std::string cmCPackNSISGenerator::TranslateNewlines(std::string str)
{
cmSystemTools::ReplaceString(str, "\n", "$\\r$\\n");
diff --git a/Source/CPack/cmCPackNSISGenerator.h b/Source/CPack/cmCPackNSISGenerator.h
index ae03e6b..bd7d752 100644
--- a/Source/CPack/cmCPackNSISGenerator.h
+++ b/Source/CPack/cmCPackNSISGenerator.h
@@ -84,6 +84,11 @@ protected:
std::string CreateComponentGroupDescription(cmCPackComponentGroup* group,
std::ostream& macrosOut);
+ /// Returns the custom install directory if available for the specified
+ /// component, otherwise $INSTDIR is returned.
+ std::string CustomComponentInstallDirectory(
+ const std::string& componentName);
+
/// Translations any newlines found in the string into \\r\\n, so that the
/// resulting string can be used within NSIS.
static std::string TranslateNewlines(std::string str);
diff --git a/Source/Checks/cm_cxx_auto_ptr.cxx b/Source/Checks/cm_cxx_auto_ptr.cxx
new file mode 100644
index 0000000..d3100fd
--- /dev/null
+++ b/Source/Checks/cm_cxx_auto_ptr.cxx
@@ -0,0 +1,18 @@
+#include <memory>
+
+std::auto_ptr<int> get_auto_ptr()
+{
+ std::auto_ptr<int> ptr;
+ ptr = std::auto_ptr<int>(new int(0));
+ return ptr;
+}
+
+int use_auto_ptr(std::auto_ptr<int> ptr)
+{
+ return *ptr;
+}
+
+int main()
+{
+ return use_auto_ptr(get_auto_ptr());
+}
diff --git a/Source/Checks/cm_cxx_features.cmake b/Source/Checks/cm_cxx_features.cmake
index c6a532f..80c9f3b 100644
--- a/Source/Checks/cm_cxx_features.cmake
+++ b/Source/Checks/cm_cxx_features.cmake
@@ -32,6 +32,7 @@ function(cm_check_cxx_feature name)
endfunction()
if(CMAKE_CXX_STANDARD)
+ cm_check_cxx_feature(auto_ptr)
cm_check_cxx_feature(make_unique)
if(CMake_HAVE_CXX_MAKE_UNIQUE)
set(CMake_HAVE_CXX_UNIQUE_PTR 1)
diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx
index 4de4bef..52809b0 100644
--- a/Source/QtDialog/CMakeSetup.cxx
+++ b/Source/QtDialog/CMakeSetup.cxx
@@ -109,11 +109,13 @@ int main(int argc, char** argv)
QTextCodec::setCodecForLocale(utf8_codec);
#endif
+#if QT_VERSION < 0x050000
// clean out standard Qt paths for plugins, which we don't use anyway
// when creating Mac bundles, it potentially causes problems
foreach (QString p, QApplication::libraryPaths()) {
QApplication::removeLibraryPath(p);
}
+#endif
// tell the cmake library where cmake is
QDir cmExecDir(QApplication::applicationDirPath());
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
index 6523e3e..9b5248e 100644
--- a/Source/cmCTest.cxx
+++ b/Source/cmCTest.cxx
@@ -1506,22 +1506,17 @@ std::string cmCTest::Base64EncodeFile(std::string const& file)
| std::ios::binary
#endif
);
- unsigned char* file_buffer = new unsigned char[len + 1];
- ifs.read(reinterpret_cast<char*>(file_buffer), len);
+ std::vector<char> file_buffer(len + 1);
+ ifs.read(&file_buffer[0], len);
ifs.close();
- unsigned char* encoded_buffer = new unsigned char[(len * 3) / 2 + 5];
+ std::vector<char> encoded_buffer((len * 3) / 2 + 5);
- size_t const rlen = cmsysBase64_Encode(file_buffer, len, encoded_buffer, 1);
+ size_t const rlen = cmsysBase64_Encode(
+ reinterpret_cast<unsigned char*>(&file_buffer[0]), len,
+ reinterpret_cast<unsigned char*>(&encoded_buffer[0]), 1);
- std::string base64 = "";
- for (size_t i = 0; i < rlen; i++) {
- base64 += encoded_buffer[i];
- }
- delete[] file_buffer;
- delete[] encoded_buffer;
-
- return base64;
+ return std::string(&encoded_buffer[0], rlen);
}
bool cmCTest::SubmitExtraFiles(const VectorOfStrings& files)
@@ -2795,48 +2790,42 @@ bool cmCTest::CompressString(std::string& str)
int ret;
z_stream strm;
- unsigned char* in =
- reinterpret_cast<unsigned char*>(const_cast<char*>(str.c_str()));
- // zlib makes the guarantee that this is the maximum output size
- int outSize =
- static_cast<int>(static_cast<double>(str.size()) * 1.001 + 13.0);
- unsigned char* out = new unsigned char[outSize];
-
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
ret = deflateInit(&strm, -1); // default compression level
if (ret != Z_OK) {
- delete[] out;
return false;
}
+ unsigned char* in =
+ reinterpret_cast<unsigned char*>(const_cast<char*>(str.c_str()));
+ // zlib makes the guarantee that this is the maximum output size
+ int outSize =
+ static_cast<int>(static_cast<double>(str.size()) * 1.001 + 13.0);
+ std::vector<unsigned char> out(outSize);
+
strm.avail_in = static_cast<uInt>(str.size());
strm.next_in = in;
strm.avail_out = outSize;
- strm.next_out = out;
+ strm.next_out = &out[0];
ret = deflate(&strm, Z_FINISH);
if (ret == Z_STREAM_ERROR || ret != Z_STREAM_END) {
cmCTestLog(this, ERROR_MESSAGE, "Error during gzip compression."
<< std::endl);
- delete[] out;
return false;
}
(void)deflateEnd(&strm);
// Now base64 encode the resulting binary string
- unsigned char* base64EncodedBuffer = new unsigned char[(outSize * 3) / 2];
+ std::vector<unsigned char> base64EncodedBuffer((outSize * 3) / 2);
size_t rlen =
- cmsysBase64_Encode(out, strm.total_out, base64EncodedBuffer, 1);
-
- str = "";
- str.append(reinterpret_cast<char*>(base64EncodedBuffer), rlen);
+ cmsysBase64_Encode(&out[0], strm.total_out, &base64EncodedBuffer[0], 1);
- delete[] base64EncodedBuffer;
- delete[] out;
+ str.assign(reinterpret_cast<char*>(&base64EncodedBuffer[0]), rlen);
return true;
}
diff --git a/Source/cmConfigure.cmake.h.in b/Source/cmConfigure.cmake.h.in
index 8365367..8a1e81f 100644
--- a/Source/cmConfigure.cmake.h.in
+++ b/Source/cmConfigure.cmake.h.in
@@ -30,6 +30,7 @@
#cmakedefine CMAKE_USE_MACH_PARSER
#cmakedefine CMAKE_USE_LIBUV
#cmakedefine CMAKE_ENCODING_UTF8
+#cmakedefine CMake_HAVE_CXX_AUTO_PTR
#cmakedefine CMake_HAVE_CXX_MAKE_UNIQUE
#cmakedefine CMake_HAVE_CXX_NULLPTR
#cmakedefine CMake_HAVE_CXX_OVERRIDE
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 4772474..95747f2 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -319,6 +319,12 @@ void cmGlobalGenerator::FindMakeProgram(cmMakefile* mf)
}
}
+bool cmGlobalGenerator::CheckLanguages(
+ std::vector<std::string> const& /* languages */, cmMakefile* /* mf */) const
+{
+ return true;
+}
+
// enable the given language
//
// The following files are loaded in this order:
@@ -428,6 +434,10 @@ void cmGlobalGenerator::EnableLanguage(
// find and make sure CMAKE_MAKE_PROGRAM is defined
this->FindMakeProgram(mf);
+ if (!this->CheckLanguages(languages, mf)) {
+ return;
+ }
+
// try and load the CMakeSystem.cmake if it is there
std::string fpath = rootBin;
bool const readCMakeSystem = !mf->GetDefinition("CMAKE_SYSTEM_LOADED");
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index f7b2e59..7bc389d 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -381,6 +381,8 @@ protected:
void SetLanguageEnabledFlag(const std::string& l, cmMakefile* mf);
void SetLanguageEnabledMaps(const std::string& l, cmMakefile* mf);
void FillExtensionToLanguageMap(const std::string& l, cmMakefile* mf);
+ virtual bool CheckLanguages(std::vector<std::string> const& languages,
+ cmMakefile* mf) const;
virtual void PrintCompilerAdvice(std::ostream& os, std::string const& lang,
const char* envVar) const;
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index b913621..81690e7 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -14,6 +14,7 @@
#include "cmAlgorithms.h"
#include "cmDocumentationEntry.h"
+#include "cmFortranParser.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpressionEvaluationFile.h"
#include "cmGeneratorTarget.h"
@@ -26,8 +27,12 @@
#include "cmTarget.h"
#include "cmTargetDepend.h"
#include "cmVersion.h"
+#include "cm_auto_ptr.hxx"
#include "cmake.h"
+#include "cm_jsoncpp_reader.h"
+#include "cm_jsoncpp_writer.h"
+
#include <algorithm>
#include <ctype.h>
#include <functional>
@@ -473,6 +478,9 @@ cmGlobalNinjaGenerator::cmGlobalNinjaGenerator(cmake* cm)
, UsingGCCOnWindows(false)
, ComputingUnknownDependencies(false)
, PolicyCMP0058(cmPolicies::WARN)
+ , NinjaSupportsConsolePool(false)
+ , NinjaSupportsImplicitOuts(false)
+ , NinjaSupportsDyndeps(0)
{
#ifdef _WIN32
cm->GetState()->SetWindowsShell(true);
@@ -558,15 +566,81 @@ void cmGlobalNinjaGenerator::FindMakeProgram(cmMakefile* mf)
cmSystemTools::RunSingleCommand(command, &version, CM_NULLPTR, CM_NULLPTR,
CM_NULLPTR, cmSystemTools::OUTPUT_NONE);
this->NinjaVersion = cmSystemTools::TrimWhitespace(version);
+ this->CheckNinjaFeatures();
}
}
+void cmGlobalNinjaGenerator::CheckNinjaFeatures()
+{
+ this->NinjaSupportsConsolePool = !cmSystemTools::VersionCompare(
+ cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
+ RequiredNinjaVersionForConsolePool().c_str());
+ this->NinjaSupportsImplicitOuts = !cmSystemTools::VersionCompare(
+ cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
+ this->RequiredNinjaVersionForImplicitOuts().c_str());
+ {
+ // Our ninja branch adds ".dyndep-#" to its version number,
+ // where '#' is a feature-specific version number. Extract it.
+ static std::string const k_DYNDEP_ = ".dyndep-";
+ std::string::size_type pos = this->NinjaVersion.find(k_DYNDEP_);
+ if (pos != std::string::npos) {
+ const char* fv = this->NinjaVersion.c_str() + pos + k_DYNDEP_.size();
+ cmSystemTools::StringToULong(fv, &this->NinjaSupportsDyndeps);
+ }
+ }
+}
+
+bool cmGlobalNinjaGenerator::CheckLanguages(
+ std::vector<std::string> const& languages, cmMakefile* mf) const
+{
+ if (std::find(languages.begin(), languages.end(), "Fortran") !=
+ languages.end()) {
+ return this->CheckFortran(mf);
+ }
+ return true;
+}
+
+bool cmGlobalNinjaGenerator::CheckFortran(cmMakefile* mf) const
+{
+ if (this->NinjaSupportsDyndeps == 1) {
+ return true;
+ }
+
+ std::ostringstream e;
+ if (this->NinjaSupportsDyndeps == 0) {
+ /* clang-format off */
+ e <<
+ "The Ninja generator does not support Fortran using Ninja version\n"
+ " " + this->NinjaVersion + "\n"
+ "due to lack of required features. "
+ "Kitware has implemented the required features but as of this version "
+ "of CMake they have not been integrated to upstream ninja. "
+ "Pending integration, Kitware maintains a branch at:\n"
+ " https://github.com/Kitware/ninja/tree/features-for-fortran#readme\n"
+ "with the required features. "
+ "One may build ninja from that branch to get support for Fortran."
+ ;
+ /* clang-format on */
+ } else {
+ /* clang-format off */
+ e <<
+ "The Ninja generator in this version of CMake does not support Fortran "
+ "using Ninja version\n"
+ " " + this->NinjaVersion + "\n"
+ "because its 'dyndep' feature version is " <<
+ this->NinjaSupportsDyndeps << ". "
+ "This version of CMake is aware only of 'dyndep' feature version 1."
+ ;
+ /* clang-format on */
+ }
+ mf->IssueMessage(cmake::FATAL_ERROR, e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+}
+
void cmGlobalNinjaGenerator::EnableLanguage(
std::vector<std::string> const& langs, cmMakefile* mf, bool optional)
{
- if (std::find(langs.begin(), langs.end(), "Fortran") != langs.end()) {
- cmSystemTools::Error("The Ninja generator does not support Fortran yet.");
- }
this->cmGlobalGenerator::EnableLanguage(langs, mf, optional);
for (std::vector<std::string>::const_iterator l = langs.begin();
l != langs.end(); ++l) {
@@ -1301,16 +1375,12 @@ std::string cmGlobalNinjaGenerator::ninjaCmd() const
bool cmGlobalNinjaGenerator::SupportsConsolePool() const
{
- return !cmSystemTools::VersionCompare(
- cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
- RequiredNinjaVersionForConsolePool().c_str());
+ return this->NinjaSupportsConsolePool;
}
bool cmGlobalNinjaGenerator::SupportsImplicitOuts() const
{
- return !cmSystemTools::VersionCompare(
- cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
- this->RequiredNinjaVersionForImplicitOuts().c_str());
+ return this->NinjaSupportsImplicitOuts;
}
void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os)
@@ -1378,3 +1448,421 @@ void cmGlobalNinjaGenerator::StripNinjaOutputPathPrefixAsSuffix(
EnsureTrailingSlash(path);
cmStripSuffixIfExists(path, this->OutputPathPrefix);
}
+
+/*
+
+We use the following approach to support Fortran. Each target already
+has a <target>.dir/ directory used to hold intermediate files for CMake.
+For each target, a FortranDependInfo.json file is generated by CMake with
+information about include directories, module directories, and the locations
+the per-target directories for target dependencies.
+
+Compilation of source files within a target is split into the following steps:
+
+1. Preprocess all sources, scan preprocessed output for module dependencies.
+ This step is done with independent build statements for each source,
+ and can therefore be done in parallel.
+
+ rule Fortran_PREPROCESS
+ depfile = $DEP_FILE
+ command = gfortran -cpp $DEFINES $INCLUDES $FLAGS -E $in -o $out &&
+ cmake -E cmake_ninja_depends \
+ --tdi=FortranDependInfo.json --pp=$out --dep=$DEP_FILE \
+ --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE
+
+ build src.f90-pp.f90 | src.f90-pp.f90.ddi: Fortran_PREPROCESS src.f90
+ OBJ_FILE = src.f90.o
+ DEP_FILE = src.f90-pp.f90.d
+ DYNDEP_INTERMEDIATE_FILE = src.f90-pp.f90.ddi
+
+ The ``cmake -E cmake_ninja_depends`` tool reads the preprocessed output
+ and generates the ninja depfile for preprocessor dependencies. It also
+ generates a "ddi" file (in a format private to CMake) that lists the
+ object file that compilation will produce along with the module names
+ it provides and/or requires. The "ddi" file is an implicit output
+ because it should not appear in "$out" but is generated by the rule.
+
+2. Consolidate the per-source module dependencies saved in the "ddi"
+ files from all sources to produce a ninja "dyndep" file, ``Fortran.dd``.
+
+ rule Fortran_DYNDEP
+ command = cmake -E cmake_ninja_dyndep \
+ --tdi=FortranDependInfo.json --dd=$out $in
+
+ build Fortran.dd: Fortran_DYNDEP src1.f90-pp.f90.ddi src2.f90-pp.f90.ddi
+
+ The ``cmake -E cmake_ninja_dyndep`` tool reads the "ddi" files from all
+ sources in the target and the ``FortranModules.json`` files from targets
+ on which the target depends. It computes dependency edges on compilations
+ that require modules to those that provide the modules. This information
+ is placed in the ``Fortran.dd`` file for ninja to load later. It also
+ writes the expected location of modules provided by this target into
+ ``FortranModules.json`` for use by dependent targets.
+
+3. Compile all sources after loading dynamically discovered dependencies
+ of the compilation build statements from their ``dyndep`` bindings.
+
+ rule Fortran_COMPILE
+ command = gfortran $INCLUDES $FLAGS -c $in -o $out
+
+ build src1.f90.o: Fortran_COMPILE src1.f90-pp.f90 || Fortran.dd
+ dyndep = Fortran.dd
+
+ The "dyndep" binding tells ninja to load dynamically discovered
+ dependency information from ``Fortran.dd``. This adds information
+ such as:
+
+ build src1.f90.o | mod1.mod: dyndep
+ restat = 1
+
+ This tells ninja that ``mod1.mod`` is an implicit output of compiling
+ the object file ``src1.f90.o``. The ``restat`` binding tells it that
+ the timestamp of the output may not always change. Additionally:
+
+ build src2.f90.o: dyndep | mod1.mod
+
+ This tells ninja that ``mod1.mod`` is a dependency of compiling the
+ object file ``src2.f90.o``. This ensures that ``src1.f90.o`` and
+ ``mod1.mod`` will always be up to date before ``src2.f90.o`` is built
+ (because the latter consumes the module).
+*/
+
+int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
+ std::vector<std::string>::const_iterator argEnd)
+{
+ std::string arg_tdi;
+ std::string arg_pp;
+ std::string arg_dep;
+ std::string arg_obj;
+ std::string arg_ddi;
+ for (std::vector<std::string>::const_iterator a = argBeg; a != argEnd; ++a) {
+ std::string const& arg = *a;
+ if (cmHasLiteralPrefix(arg, "--tdi=")) {
+ arg_tdi = arg.substr(6);
+ } else if (cmHasLiteralPrefix(arg, "--pp=")) {
+ arg_pp = arg.substr(5);
+ } else if (cmHasLiteralPrefix(arg, "--dep=")) {
+ arg_dep = arg.substr(6);
+ } else if (cmHasLiteralPrefix(arg, "--obj=")) {
+ arg_obj = arg.substr(6);
+ } else if (cmHasLiteralPrefix(arg, "--ddi=")) {
+ arg_ddi = arg.substr(6);
+ } else {
+ cmSystemTools::Error("-E cmake_ninja_depends unknown argument: ",
+ arg.c_str());
+ return 1;
+ }
+ }
+ if (arg_tdi.empty()) {
+ cmSystemTools::Error("-E cmake_ninja_depends requires value for --tdi=");
+ return 1;
+ }
+ if (arg_pp.empty()) {
+ cmSystemTools::Error("-E cmake_ninja_depends requires value for --pp=");
+ return 1;
+ }
+ if (arg_dep.empty()) {
+ cmSystemTools::Error("-E cmake_ninja_depends requires value for --dep=");
+ return 1;
+ }
+ if (arg_obj.empty()) {
+ cmSystemTools::Error("-E cmake_ninja_depends requires value for --obj=");
+ return 1;
+ }
+ if (arg_ddi.empty()) {
+ cmSystemTools::Error("-E cmake_ninja_depends requires value for --ddi=");
+ return 1;
+ }
+
+ std::vector<std::string> includes;
+ {
+ Json::Value tdio;
+ Json::Value const& tdi = tdio;
+ {
+ cmsys::ifstream tdif(arg_tdi.c_str(), std::ios::in | std::ios::binary);
+ Json::Reader reader;
+ if (!reader.parse(tdif, tdio, false)) {
+ cmSystemTools::Error("-E cmake_ninja_depends failed to parse ",
+ arg_tdi.c_str(),
+ reader.getFormattedErrorMessages().c_str());
+ return 1;
+ }
+ }
+
+ Json::Value const& tdi_include_dirs = tdi["include-dirs"];
+ if (tdi_include_dirs.isArray()) {
+ for (Json::Value::const_iterator i = tdi_include_dirs.begin();
+ i != tdi_include_dirs.end(); ++i) {
+ includes.push_back(i->asString());
+ }
+ }
+ }
+
+ cmFortranSourceInfo info;
+ std::set<std::string> defines;
+ cmFortranParser parser(includes, defines, info);
+ if (!cmFortranParser_FilePush(&parser, arg_pp.c_str())) {
+ cmSystemTools::Error("-E cmake_ninja_depends failed to open ",
+ arg_pp.c_str());
+ return 1;
+ }
+ if (cmFortran_yyparse(parser.Scanner) != 0) {
+ // Failed to parse the file.
+ return 1;
+ }
+
+ {
+ cmGeneratedFileStream depfile(arg_dep.c_str());
+ depfile << cmSystemTools::ConvertToUnixOutputPath(arg_pp) << ":";
+ for (std::set<std::string>::iterator i = info.Includes.begin();
+ i != info.Includes.end(); ++i) {
+ depfile << " \\\n " << cmSystemTools::ConvertToUnixOutputPath(*i);
+ }
+ depfile << "\n";
+ }
+
+ Json::Value ddi(Json::objectValue);
+ ddi["object"] = arg_obj;
+
+ Json::Value& ddi_provides = ddi["provides"] = Json::arrayValue;
+ for (std::set<std::string>::iterator i = info.Provides.begin();
+ i != info.Provides.end(); ++i) {
+ ddi_provides.append(*i);
+ }
+ Json::Value& ddi_requires = ddi["requires"] = Json::arrayValue;
+ for (std::set<std::string>::iterator i = info.Requires.begin();
+ i != info.Requires.end(); ++i) {
+ // Require modules not provided in the same source.
+ if (!info.Provides.count(*i)) {
+ ddi_requires.append(*i);
+ }
+ }
+
+ cmGeneratedFileStream ddif(arg_ddi.c_str());
+ ddif << ddi;
+ if (!ddif) {
+ cmSystemTools::Error("-E cmake_ninja_depends failed to write ",
+ arg_ddi.c_str());
+ return 1;
+ }
+ return 0;
+}
+
+struct cmFortranObjectInfo
+{
+ std::string Object;
+ std::vector<std::string> Provides;
+ std::vector<std::string> Requires;
+};
+
+bool cmGlobalNinjaGenerator::WriteDyndepFile(
+ std::string const& dir_top_src, std::string const& dir_top_bld,
+ std::string const& dir_cur_src, std::string const& dir_cur_bld,
+ std::string const& arg_dd, std::vector<std::string> const& arg_ddis,
+ std::string const& module_dir,
+ std::vector<std::string> const& linked_target_dirs)
+{
+ // Setup path conversions.
+ {
+ cmState::Snapshot snapshot =
+ this->GetCMakeInstance()->GetCurrentSnapshot();
+ snapshot.GetDirectory().SetCurrentSource(dir_cur_src);
+ snapshot.GetDirectory().SetCurrentBinary(dir_cur_bld);
+ snapshot.GetDirectory().SetRelativePathTopSource(dir_top_src.c_str());
+ snapshot.GetDirectory().SetRelativePathTopBinary(dir_top_bld.c_str());
+ CM_AUTO_PTR<cmMakefile> mfd(new cmMakefile(this, snapshot));
+ CM_AUTO_PTR<cmLocalNinjaGenerator> lgd(static_cast<cmLocalNinjaGenerator*>(
+ this->CreateLocalGenerator(mfd.get())));
+ this->Makefiles.push_back(mfd.release());
+ this->LocalGenerators.push_back(lgd.release());
+ }
+
+ std::vector<cmFortranObjectInfo> objects;
+ for (std::vector<std::string>::const_iterator ddii = arg_ddis.begin();
+ ddii != arg_ddis.end(); ++ddii) {
+ // Load the ddi file and compute the module file paths it provides.
+ Json::Value ddio;
+ Json::Value const& ddi = ddio;
+ cmsys::ifstream ddif(ddii->c_str(), std::ios::in | std::ios::binary);
+ Json::Reader reader;
+ if (!reader.parse(ddif, ddio, false)) {
+ cmSystemTools::Error("-E cmake_ninja_dyndep failed to parse ",
+ ddii->c_str(),
+ reader.getFormattedErrorMessages().c_str());
+ return false;
+ }
+
+ cmFortranObjectInfo info;
+ info.Object = ddi["object"].asString();
+ Json::Value const& ddi_provides = ddi["provides"];
+ if (ddi_provides.isArray()) {
+ for (Json::Value::const_iterator i = ddi_provides.begin();
+ i != ddi_provides.end(); ++i) {
+ info.Provides.push_back(i->asString());
+ }
+ }
+ Json::Value const& ddi_requires = ddi["requires"];
+ if (ddi_requires.isArray()) {
+ for (Json::Value::const_iterator i = ddi_requires.begin();
+ i != ddi_requires.end(); ++i) {
+ info.Requires.push_back(i->asString());
+ }
+ }
+ objects.push_back(info);
+ }
+
+ // Map from module name to module file path, if known.
+ std::map<std::string, std::string> mod_files;
+
+ // Populate the module map with those provided by linked targets first.
+ for (std::vector<std::string>::const_iterator di =
+ linked_target_dirs.begin();
+ di != linked_target_dirs.end(); ++di) {
+ std::string const ltmn = *di + "/FortranModules.json";
+ Json::Value ltm;
+ cmsys::ifstream ltmf(ltmn.c_str(), std::ios::in | std::ios::binary);
+ Json::Reader reader;
+ if (ltmf && !reader.parse(ltmf, ltm, false)) {
+ cmSystemTools::Error("-E cmake_ninja_dyndep failed to parse ",
+ di->c_str(),
+ reader.getFormattedErrorMessages().c_str());
+ return false;
+ }
+ if (ltm.isObject()) {
+ for (Json::Value::iterator i = ltm.begin(); i != ltm.end(); ++i) {
+ mod_files[i.key().asString()] = i->asString();
+ }
+ }
+ }
+
+ // Extend the module map with those provided by this target.
+ // We do this after loading the modules provided by linked targets
+ // in case we have one of the same name that must be preferred.
+ Json::Value tm = Json::objectValue;
+ for (std::vector<cmFortranObjectInfo>::iterator oi = objects.begin();
+ oi != objects.end(); ++oi) {
+ for (std::vector<std::string>::iterator i = oi->Provides.begin();
+ i != oi->Provides.end(); ++i) {
+ std::string const mod = module_dir + *i + ".mod";
+ mod_files[*i] = mod;
+ tm[*i] = mod;
+ }
+ }
+
+ cmGeneratedFileStream ddf(arg_dd.c_str());
+ ddf << "ninja_dyndep_version = 1.0\n";
+
+ for (std::vector<cmFortranObjectInfo>::iterator oi = objects.begin();
+ oi != objects.end(); ++oi) {
+ std::string const ddComment;
+ std::string const ddRule = "dyndep";
+ cmNinjaDeps ddOutputs;
+ cmNinjaDeps ddImplicitOuts;
+ cmNinjaDeps ddExplicitDeps;
+ cmNinjaDeps ddImplicitDeps;
+ cmNinjaDeps ddOrderOnlyDeps;
+ cmNinjaVars ddVars;
+
+ ddOutputs.push_back(oi->Object);
+ for (std::vector<std::string>::iterator i = oi->Provides.begin();
+ i != oi->Provides.end(); ++i) {
+ ddImplicitOuts.push_back(this->ConvertToNinjaPath(mod_files[*i]));
+ }
+ for (std::vector<std::string>::iterator i = oi->Requires.begin();
+ i != oi->Requires.end(); ++i) {
+ std::map<std::string, std::string>::iterator m = mod_files.find(*i);
+ if (m != mod_files.end()) {
+ ddImplicitDeps.push_back(this->ConvertToNinjaPath(m->second));
+ }
+ }
+ if (!oi->Provides.empty()) {
+ ddVars["restat"] = "1";
+ }
+
+ this->WriteBuild(ddf, ddComment, ddRule, ddOutputs, ddImplicitOuts,
+ ddExplicitDeps, ddImplicitDeps, ddOrderOnlyDeps, ddVars);
+ }
+
+ // Store the map of modules provided by this target in a file for
+ // use by dependents that reference this target in linked-target-dirs.
+ std::string const target_mods_file =
+ cmSystemTools::GetFilenamePath(arg_dd) + "/FortranModules.json";
+ cmGeneratedFileStream tmf(target_mods_file.c_str());
+ tmf << tm;
+
+ return true;
+}
+
+int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
+ std::vector<std::string>::const_iterator argEnd)
+{
+ std::string arg_dd;
+ std::string arg_tdi;
+ std::vector<std::string> arg_ddis;
+ for (std::vector<std::string>::const_iterator a = argBeg; a != argEnd; ++a) {
+ std::string const& arg = *a;
+ if (cmHasLiteralPrefix(arg, "--tdi=")) {
+ arg_tdi = arg.substr(6);
+ } else if (cmHasLiteralPrefix(arg, "--dd=")) {
+ arg_dd = arg.substr(5);
+ } else if (!cmHasLiteralPrefix(arg, "--") &&
+ cmHasLiteralSuffix(arg, ".ddi")) {
+ arg_ddis.push_back(arg);
+ } else {
+ cmSystemTools::Error("-E cmake_ninja_dyndep unknown argument: ",
+ arg.c_str());
+ return 1;
+ }
+ }
+ if (arg_tdi.empty()) {
+ cmSystemTools::Error("-E cmake_ninja_dyndep requires value for --tdi=");
+ return 1;
+ }
+ if (arg_dd.empty()) {
+ cmSystemTools::Error("-E cmake_ninja_dyndep requires value for --dd=");
+ return 1;
+ }
+
+ Json::Value tdio;
+ Json::Value const& tdi = tdio;
+ {
+ cmsys::ifstream tdif(arg_tdi.c_str(), std::ios::in | std::ios::binary);
+ Json::Reader reader;
+ if (!reader.parse(tdif, tdio, false)) {
+ cmSystemTools::Error("-E cmake_ninja_dyndep failed to parse ",
+ arg_tdi.c_str(),
+ reader.getFormattedErrorMessages().c_str());
+ return 1;
+ }
+ }
+
+ std::string const dir_cur_bld = tdi["dir-cur-bld"].asString();
+ std::string const dir_cur_src = tdi["dir-cur-src"].asString();
+ std::string const dir_top_bld = tdi["dir-top-bld"].asString();
+ std::string const dir_top_src = tdi["dir-top-src"].asString();
+ std::string module_dir = tdi["module-dir"].asString();
+ if (!module_dir.empty()) {
+ module_dir += "/";
+ }
+ std::vector<std::string> linked_target_dirs;
+ Json::Value const& tdi_linked_target_dirs = tdi["linked-target-dirs"];
+ if (tdi_linked_target_dirs.isArray()) {
+ for (Json::Value::const_iterator i = tdi_linked_target_dirs.begin();
+ i != tdi_linked_target_dirs.end(); ++i) {
+ linked_target_dirs.push_back(i->asString());
+ }
+ }
+
+ cmake cm;
+ cm.SetHomeDirectory(dir_top_src);
+ cm.SetHomeOutputDirectory(dir_top_bld);
+ CM_AUTO_PTR<cmGlobalNinjaGenerator> ggd(
+ static_cast<cmGlobalNinjaGenerator*>(cm.CreateGlobalGenerator("Ninja")));
+ if (!ggd.get() ||
+ !ggd->WriteDyndepFile(dir_top_src, dir_top_bld, dir_cur_src, dir_cur_bld,
+ arg_dd, arg_ddis, module_dir,
+ linked_target_dirs)) {
+ return 1;
+ }
+ return 0;
+}
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index 0201685..76430a0 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -347,6 +347,15 @@ public:
bool HasOutputPathPrefix() const { return !this->OutputPathPrefix.empty(); }
void StripNinjaOutputPathPrefixAsSuffix(std::string& path);
+ bool WriteDyndepFile(std::string const& dir_top_src,
+ std::string const& dir_top_bld,
+ std::string const& dir_cur_src,
+ std::string const& dir_cur_bld,
+ std::string const& arg_dd,
+ std::vector<std::string> const& arg_ddis,
+ std::string const& module_dir,
+ std::vector<std::string> const& linked_target_dirs);
+
protected:
void Generate() CM_OVERRIDE;
@@ -355,6 +364,10 @@ protected:
private:
std::string GetEditCacheCommand() const CM_OVERRIDE;
void FindMakeProgram(cmMakefile* mf) CM_OVERRIDE;
+ void CheckNinjaFeatures();
+ bool CheckLanguages(std::vector<std::string> const& languages,
+ cmMakefile* mf) const CM_OVERRIDE;
+ bool CheckFortran(cmMakefile* mf) const;
void OpenBuildFileStream();
void CloseBuildFileStream();
@@ -439,6 +452,9 @@ private:
std::string NinjaCommand;
std::string NinjaVersion;
+ bool NinjaSupportsConsolePool;
+ bool NinjaSupportsImplicitOuts;
+ unsigned long NinjaSupportsDyndeps;
private:
void InitOutputPathPrefix();
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 997f46c..0d5de06 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -2996,6 +2996,15 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects(
buildSettings->AddAttribute("GCC_VERSION",
this->CreateString(this->GeneratorToolset));
}
+ if (this->GetLanguageEnabled("Swift")) {
+ std::string swiftVersion = "2.3";
+ if (const char* vers = this->CurrentMakefile->GetDefinition(
+ "CMAKE_Swift_LANGUAGE_VERSION")) {
+ swiftVersion = vers;
+ }
+ buildSettings->AddAttribute("SWIFT_VERSION",
+ this->CreateString(swiftVersion));
+ }
std::string symroot = root->GetCurrentBinaryDirectory();
symroot += "/build";
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index fb09bfe..f88eb7b 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -29,6 +29,8 @@
#include "cmSystemTools.h"
#include "cmake.h"
+#include "cm_jsoncpp_writer.h"
+
#include <algorithm>
#include <iterator>
#include <map>
@@ -93,6 +95,31 @@ std::string cmNinjaTargetGenerator::LanguageCompilerRule(
cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName());
}
+std::string cmNinjaTargetGenerator::LanguagePreprocessRule(
+ std::string const& lang) const
+{
+ return lang + "_PREPROCESS__" +
+ cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName());
+}
+
+bool cmNinjaTargetGenerator::NeedExplicitPreprocessing(
+ std::string const& lang) const
+{
+ return lang == "Fortran";
+}
+
+std::string cmNinjaTargetGenerator::LanguageDyndepRule(
+ const std::string& lang) const
+{
+ return lang + "_DYNDEP__" +
+ cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName());
+}
+
+bool cmNinjaTargetGenerator::NeedDyndep(std::string const& lang) const
+{
+ return lang == "Fortran";
+}
+
std::string cmNinjaTargetGenerator::OrderDependsTargetForTarget()
{
return "cmake_order_depends_target_" + this->GetTargetName();
@@ -229,6 +256,64 @@ std::string cmNinjaTargetGenerator::GetObjectFilePath(
return path;
}
+std::string cmNinjaTargetGenerator::GetPreprocessedFilePath(
+ cmSourceFile const* source) const
+{
+ // Choose an extension to compile already-preprocessed source.
+ std::string ppExt = source->GetExtension();
+ if (cmHasLiteralPrefix(ppExt, "F")) {
+ // Some Fortran compilers automatically enable preprocessing for
+ // upper-case extensions. Since the source is already preprocessed,
+ // use a lower-case extension.
+ ppExt = cmSystemTools::LowerCase(ppExt);
+ }
+ if (ppExt == "fpp") {
+ // Some Fortran compilers automatically enable preprocessing for
+ // the ".fpp" extension. Since the source is already preprocessed,
+ // use the ".f" extension.
+ ppExt = "f";
+ }
+
+ // Take the object file name and replace the extension.
+ std::string const& objName = this->GeneratorTarget->GetObjectName(source);
+ std::string const& objExt =
+ this->GetGlobalGenerator()->GetLanguageOutputExtension(*source);
+ assert(objName.size() >= objExt.size());
+ std::string const ppName =
+ objName.substr(0, objName.size() - objExt.size()) + "-pp." + ppExt;
+
+ std::string path = this->LocalGenerator->GetHomeRelativeOutputPath();
+ if (!path.empty())
+ path += "/";
+ path += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ path += "/";
+ path += ppName;
+ return path;
+}
+
+std::string cmNinjaTargetGenerator::GetDyndepFilePath(
+ std::string const& lang) const
+{
+ std::string path = this->LocalGenerator->GetHomeRelativeOutputPath();
+ if (!path.empty())
+ path += "/";
+ path += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ path += "/";
+ path += lang;
+ path += ".dd";
+ return path;
+}
+
+std::string cmNinjaTargetGenerator::GetTargetDependInfoPath(
+ std::string const& lang) const
+{
+ std::string path = this->Makefile->GetCurrentBinaryDirectory();
+ path += "/";
+ path += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ path += "/" + lang + "DependInfo.json";
+ return path;
+}
+
std::string cmNinjaTargetGenerator::GetTargetOutputDir() const
{
std::string dir = this->GeneratorTarget->GetDirectory(this->GetConfigName());
@@ -311,6 +396,10 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
vars.ObjectDir = "$OBJECT_DIR";
vars.ObjectFileDir = "$OBJECT_FILE_DIR";
+ // For some cases we do an explicit preprocessor invocation.
+ bool const explicitPP = this->NeedExplicitPreprocessing(lang);
+ bool const needDyndep = this->NeedDyndep(lang);
+
cmMakefile* mf = this->GetMakefile();
std::string flags = "$FLAGS";
@@ -331,7 +420,9 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
std::string deptype;
std::string depfile;
std::string cldeps;
- if (this->NeedDepTypeMSVC(lang)) {
+ if (explicitPP) {
+ // The explicit preprocessing step will handle dependency scanning.
+ } else if (this->NeedDepTypeMSVC(lang)) {
deptype = "msvc";
depfile = "";
flags += " /showIncludes";
@@ -371,6 +462,109 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
vars.Flags = flags.c_str();
vars.DependencyFile = depfile.c_str();
+ std::string const tdi = this->GetLocalGenerator()->ConvertToOutputFormat(
+ ConvertToNinjaPath(this->GetTargetDependInfoPath(lang)),
+ cmLocalGenerator::SHELL);
+
+ if (explicitPP) {
+ // Lookup the explicit preprocessing rule.
+ std::string const ppVar = "CMAKE_" + lang + "_PREPROCESS_SOURCE";
+ std::string const ppCmd =
+ this->GetMakefile()->GetRequiredDefinition(ppVar);
+
+ // Explicit preprocessing always uses a depfile.
+ std::string const ppDeptype = ""; // no deps= for multiple outputs
+ std::string const ppDepfile = "$DEP_FILE";
+
+ cmLocalGenerator::RuleVariables ppVars;
+ ppVars.RuleLauncher = vars.RuleLauncher;
+ ppVars.CMTarget = vars.CMTarget;
+ ppVars.Language = vars.Language;
+ ppVars.Object = "$out"; // for RULE_LAUNCH_COMPILE
+ ppVars.PreprocessedSource = "$out";
+ ppVars.DependencyFile = ppDepfile.c_str();
+
+ // Preprocessing uses the original source,
+ // compilation uses preprocessed output.
+ ppVars.Source = vars.Source;
+ vars.Source = "$in";
+
+ // Preprocessing and compilation use the same flags.
+ ppVars.Flags = vars.Flags;
+
+ // Move preprocessor definitions to the preprocessor rule.
+ ppVars.Defines = vars.Defines;
+ vars.Defines = "";
+
+ // Copy include directories to the preprocessor rule. The Fortran
+ // compilation rule still needs them for the INCLUDE directive.
+ ppVars.Includes = vars.Includes;
+
+ // Rule for preprocessing source file.
+ std::vector<std::string> ppCmds;
+ cmSystemTools::ExpandListArgument(ppCmd, ppCmds);
+
+ for (std::vector<std::string>::iterator i = ppCmds.begin();
+ i != ppCmds.end(); ++i) {
+ this->GetLocalGenerator()->ExpandRuleVariables(*i, ppVars);
+ }
+
+ // Run CMake dependency scanner on preprocessed output.
+ std::string const cmake = this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
+ ppCmds.push_back(
+ cmake + " -E cmake_ninja_depends"
+ " --tdi=" +
+ tdi + " --pp=$out"
+ " --dep=$DEP_FILE" +
+ (needDyndep ? " --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE" : ""));
+
+ std::string const ppCmdLine =
+ this->GetLocalGenerator()->BuildCommandLine(ppCmds);
+
+ // Write the rule for preprocessing file of the given language.
+ std::ostringstream ppComment;
+ ppComment << "Rule for preprocessing " << lang << " files.";
+ std::ostringstream ppDesc;
+ ppDesc << "Building " << lang << " preprocessed $out";
+ this->GetGlobalGenerator()->AddRule(this->LanguagePreprocessRule(lang),
+ ppCmdLine, ppDesc.str(),
+ ppComment.str(), ppDepfile, ppDeptype,
+ /*rspfile*/ "",
+ /*rspcontent*/ "",
+ /*restat*/ "",
+ /*generator*/ false);
+ }
+
+ if (needDyndep) {
+ // Write the rule for ninja dyndep file generation.
+ std::vector<std::string> ddCmds;
+
+ // Run CMake dependency scanner on preprocessed output.
+ std::string const cmake = this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
+ ddCmds.push_back(cmake + " -E cmake_ninja_dyndep"
+ " --tdi=" +
+ tdi + " --dd=$out"
+ " $in");
+
+ std::string const ddCmdLine =
+ this->GetLocalGenerator()->BuildCommandLine(ddCmds);
+
+ std::ostringstream ddComment;
+ ddComment << "Rule to generate ninja dyndep files for " << lang << ".";
+ std::ostringstream ddDesc;
+ ddDesc << "Generating " << lang << " dyndep file $out";
+ this->GetGlobalGenerator()->AddRule(
+ this->LanguageDyndepRule(lang), ddCmdLine, ddDesc.str(), ddComment.str(),
+ /*depfile*/ "",
+ /*deps*/ "",
+ /*rspfile*/ "",
+ /*rspcontent*/ "",
+ /*restat*/ "",
+ /*generator*/ false);
+ }
+
// Rule for compiling object file.
const std::string cmdVar = std::string("CMAKE_") + lang + "_COMPILE_OBJECT";
std::string compileCmd = mf->GetRequiredDefinition(cmdVar);
@@ -519,6 +713,25 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements()
this->WriteObjectBuildStatement(*si, !orderOnlyDeps.empty());
}
+ if (!this->DDIFiles.empty()) {
+ std::string const ddComment;
+ std::string const ddRule = this->LanguageDyndepRule("Fortran");
+ cmNinjaDeps ddOutputs;
+ cmNinjaDeps ddImplicitOuts;
+ cmNinjaDeps const& ddExplicitDeps = this->DDIFiles;
+ cmNinjaDeps ddImplicitDeps;
+ cmNinjaDeps ddOrderOnlyDeps;
+ cmNinjaVars ddVars;
+
+ this->WriteTargetDependInfo("Fortran");
+
+ ddOutputs.push_back(this->GetDyndepFilePath("Fortran"));
+
+ this->GetGlobalGenerator()->WriteBuild(
+ this->GetBuildFileStream(), ddComment, ddRule, ddOutputs, ddImplicitOuts,
+ ddExplicitDeps, ddImplicitDeps, ddOrderOnlyDeps, ddVars);
+ }
+
this->GetBuildFileStream() << "\n";
}
@@ -589,6 +802,89 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
orderOnlyDeps);
}
+ // For some cases we need to generate a ninja dyndep file.
+ bool const needDyndep = this->NeedDyndep(language);
+
+ // For some cases we do an explicit preprocessor invocation.
+ bool const explicitPP = this->NeedExplicitPreprocessing(language);
+ if (explicitPP) {
+ std::string const ppComment;
+ std::string const ppRule = this->LanguagePreprocessRule(language);
+ cmNinjaDeps ppOutputs;
+ cmNinjaDeps ppImplicitOuts;
+ cmNinjaDeps ppExplicitDeps;
+ cmNinjaDeps ppImplicitDeps;
+ cmNinjaDeps ppOrderOnlyDeps;
+ cmNinjaVars ppVars;
+
+ std::string const ppFileName =
+ this->ConvertToNinjaPath(this->GetPreprocessedFilePath(source));
+ ppOutputs.push_back(ppFileName);
+
+ // Move compilation dependencies to the preprocessing build statement.
+ std::swap(ppExplicitDeps, explicitDeps);
+ std::swap(ppImplicitDeps, implicitDeps);
+ std::swap(ppOrderOnlyDeps, orderOnlyDeps);
+ std::swap(ppVars["IN_ABS"], vars["IN_ABS"]);
+
+ // The actual compilation will now use the preprocessed source.
+ explicitDeps.push_back(ppFileName);
+
+ // Preprocessing and compilation use the same flags.
+ ppVars["FLAGS"] = vars["FLAGS"];
+
+ // Move preprocessor definitions to the preprocessor build statement.
+ std::swap(ppVars["DEFINES"], vars["DEFINES"]);
+
+ // Copy include directories to the preprocessor build statement. The
+ // Fortran compilation build statement still needs them for the INCLUDE
+ // directive.
+ ppVars["INCLUDES"] = vars["INCLUDES"];
+
+ // Prepend source file's original directory as an include directory
+ // so e.g. Fortran INCLUDE statements can look for files in it.
+ std::vector<std::string> sourceDirectory;
+ sourceDirectory.push_back(
+ cmSystemTools::GetParentDirectory(source->GetFullPath()));
+
+ std::string sourceDirectoryFlag = this->LocalGenerator->GetIncludeFlags(
+ sourceDirectory, this->GeneratorTarget, language, false, false,
+ this->GetConfigName());
+
+ vars["INCLUDES"] = sourceDirectoryFlag + " " + vars["INCLUDES"];
+
+ // Explicit preprocessing always uses a depfile.
+ ppVars["DEP_FILE"] =
+ cmGlobalNinjaGenerator::EncodeDepfileSpace(ppFileName + ".d");
+ // The actual compilation does not need a depfile because it
+ // depends on the already-preprocessed source.
+ vars.erase("DEP_FILE");
+
+ if (needDyndep) {
+ // Tell dependency scanner the object file that will result from
+ // compiling the preprocessed source.
+ ppVars["OBJ_FILE"] = objectFileName;
+
+ // Tell dependency scanner where to store dyndep intermediate results.
+ std::string const ddiFile = ppFileName + ".ddi";
+ ppVars["DYNDEP_INTERMEDIATE_FILE"] = ddiFile;
+ ppImplicitOuts.push_back(ddiFile);
+ this->DDIFiles.push_back(ddiFile);
+ }
+
+ this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
+ ppVars);
+
+ this->GetGlobalGenerator()->WriteBuild(
+ this->GetBuildFileStream(), ppComment, ppRule, ppOutputs, ppImplicitOuts,
+ ppExplicitDeps, ppImplicitDeps, ppOrderOnlyDeps, ppVars);
+ }
+ if (needDyndep) {
+ std::string const dyndep = this->GetDyndepFilePath(language);
+ orderOnlyDeps.push_back(dyndep);
+ vars["dyndep"] = dyndep;
+ }
+
EnsureParentDirectoryExists(objectFileName);
vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
@@ -622,6 +918,49 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
}
}
+void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang)
+{
+ Json::Value tdi(Json::objectValue);
+ tdi["language"] = lang;
+ tdi["compiler-id"] =
+ this->Makefile->GetSafeDefinition("CMAKE_" + lang + "_COMPILER_ID");
+
+ if (lang == "Fortran") {
+ std::string mod_dir = this->GeneratorTarget->GetFortranModuleDirectory(
+ this->Makefile->GetHomeOutputDirectory());
+ if (mod_dir.empty()) {
+ mod_dir = this->Makefile->GetCurrentBinaryDirectory();
+ }
+ tdi["module-dir"] = mod_dir;
+ }
+
+ tdi["dir-cur-bld"] = this->Makefile->GetCurrentBinaryDirectory();
+ tdi["dir-cur-src"] = this->Makefile->GetCurrentSourceDirectory();
+ tdi["dir-top-bld"] = this->Makefile->GetHomeOutputDirectory();
+ tdi["dir-top-src"] = this->Makefile->GetHomeDirectory();
+
+ Json::Value& tdi_include_dirs = tdi["include-dirs"] = Json::arrayValue;
+ std::vector<std::string> includes;
+ this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
+ lang, this->GetConfigName());
+ for (std::vector<std::string>::iterator i = includes.begin();
+ i != includes.end(); ++i) {
+ tdi_include_dirs.append(*i);
+ }
+
+ Json::Value& tdi_linked_target_dirs = tdi["linked-target-dirs"] =
+ Json::arrayValue;
+ std::vector<std::string> linked = this->GetLinkedTargetDirectories();
+ for (std::vector<std::string>::iterator i = linked.begin();
+ i != linked.end(); ++i) {
+ tdi_linked_target_dirs.append(*i);
+ }
+
+ std::string const tdin = this->GetTargetDependInfoPath(lang);
+ cmGeneratedFileStream tdif(tdin.c_str());
+ tdif << tdi;
+}
+
void cmNinjaTargetGenerator::ExportObjectCompileCommand(
std::string const& language, std::string const& sourceFileName,
std::string const& objectDir, std::string const& objectFileName,
diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h
index 2b26788..f5e6511 100644
--- a/Source/cmNinjaTargetGenerator.h
+++ b/Source/cmNinjaTargetGenerator.h
@@ -70,6 +70,10 @@ protected:
cmMakefile* GetMakefile() const { return this->Makefile; }
std::string LanguageCompilerRule(const std::string& lang) const;
+ std::string LanguagePreprocessRule(std::string const& lang) const;
+ bool NeedExplicitPreprocessing(std::string const& lang) const;
+ std::string LanguageDyndepRule(std::string const& lang) const;
+ bool NeedDyndep(std::string const& lang) const;
std::string OrderDependsTargetForTarget();
@@ -107,6 +111,15 @@ protected:
/// @return the object file path for the given @a source.
std::string GetObjectFilePath(cmSourceFile const* source) const;
+ /// @return the preprocessed source file path for the given @a source.
+ std::string GetPreprocessedFilePath(cmSourceFile const* source) const;
+
+ /// @return the dyndep file path for this target.
+ std::string GetDyndepFilePath(std::string const& lang) const;
+
+ /// @return the target dependency scanner info file path
+ std::string GetTargetDependInfoPath(std::string const& lang) const;
+
/// @return the file path where the target named @a name is generated.
std::string GetTargetFilePath(const std::string& name) const;
@@ -118,6 +131,7 @@ protected:
void WriteObjectBuildStatements();
void WriteObjectBuildStatement(cmSourceFile const* source,
bool writeOrderDependsTargetForTarget);
+ void WriteTargetDependInfo(std::string const& lang);
void ExportObjectCompileCommand(
std::string const& language, std::string const& sourceFileName,
@@ -161,6 +175,7 @@ private:
cmLocalNinjaGenerator* LocalGenerator;
/// List of object files for this target.
cmNinjaDeps Objects;
+ cmNinjaDeps DDIFiles; // TODO: Make per-language.
std::vector<cmCustomCommand const*> CustomCommands;
cmNinjaDeps ExtraFiles;
};
diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx
index 56cd7ba..46c1946 100644
--- a/Source/cmServer.cxx
+++ b/Source/cmServer.cxx
@@ -14,6 +14,7 @@
#include "cmServer.h"
#include "cmServerConnection.h"
+#include "cmServerDictionary.h"
#include "cmServerProtocol.h"
#include "cmSystemTools.h"
#include "cmVersionMacros.h"
@@ -28,19 +29,6 @@
#include <iostream>
#include <memory>
-static const std::string kTYPE_KEY = "type";
-static const std::string kCOOKIE_KEY = "cookie";
-static const std::string kREPLY_TO_KEY = "inReplyTo";
-static const std::string kERROR_MESSAGE_KEY = "errorMessage";
-
-static const std::string kERROR_TYPE = "error";
-static const std::string kREPLY_TYPE = "reply";
-static const std::string kPROGRESS_TYPE = "progress";
-static const std::string kMESSAGE_TYPE = "message";
-
-static const std::string kSTART_MAGIC = "[== CMake Server ==[";
-static const std::string kEND_MAGIC = "]== CMake Server ==]";
-
class cmServer::DebugInfo
{
public:
@@ -135,8 +123,9 @@ void cmServer::RegisterProtocol(cmServerProtocol* protocol)
[version](cmServerProtocol* p) {
return p->ProtocolVersion() == version;
});
- if (it == this->SupportedProtocols.end())
+ if (it == this->SupportedProtocols.end()) {
this->SupportedProtocols.push_back(protocol);
+ }
}
void cmServer::PrintHello() const
@@ -144,16 +133,16 @@ void cmServer::PrintHello() const
Json::Value hello = Json::objectValue;
hello[kTYPE_KEY] = "hello";
- Json::Value& protocolVersions = hello["supportedProtocolVersions"] =
+ Json::Value& protocolVersions = hello[kSUPPORTED_PROTOCOL_VERSIONS] =
Json::arrayValue;
for (auto const& proto : this->SupportedProtocols) {
auto version = proto->ProtocolVersion();
Json::Value tmp = Json::objectValue;
- tmp["major"] = version.first;
- tmp["minor"] = version.second;
+ tmp[kMAJOR_KEY] = version.first;
+ tmp[kMINOR_KEY] = version.second;
if (proto->IsExperimental()) {
- tmp["experimental"] = true;
+ tmp[kIS_EXPERIMENTAL_KEY] = true;
}
protocolVersions.append(tmp);
}
@@ -193,31 +182,44 @@ void cmServer::reportMessage(const char* msg, const char* title,
cmServerResponse cmServer::SetProtocolVersion(const cmServerRequest& request)
{
- if (request.Type != "handshake")
- return request.ReportError("Waiting for type \"handshake\".");
+ if (request.Type != kHANDSHAKE_TYPE) {
+ return request.ReportError("Waiting for type \"" + kHANDSHAKE_TYPE +
+ "\".");
+ }
- Json::Value requestedProtocolVersion = request.Data["protocolVersion"];
- if (requestedProtocolVersion.isNull())
- return request.ReportError(
- "\"protocolVersion\" is required for \"handshake\".");
+ Json::Value requestedProtocolVersion = request.Data[kPROTOCOL_VERSION_KEY];
+ if (requestedProtocolVersion.isNull()) {
+ return request.ReportError("\"" + kPROTOCOL_VERSION_KEY +
+ "\" is required for \"" + kHANDSHAKE_TYPE +
+ "\".");
+ }
- if (!requestedProtocolVersion.isObject())
- return request.ReportError("\"protocolVersion\" must be a JSON object.");
+ if (!requestedProtocolVersion.isObject()) {
+ return request.ReportError("\"" + kPROTOCOL_VERSION_KEY +
+ "\" must be a JSON object.");
+ }
- Json::Value majorValue = requestedProtocolVersion["major"];
- if (!majorValue.isInt())
- return request.ReportError("\"major\" must be set and an integer.");
+ Json::Value majorValue = requestedProtocolVersion[kMAJOR_KEY];
+ if (!majorValue.isInt()) {
+ return request.ReportError("\"" + kMAJOR_KEY +
+ "\" must be set and an integer.");
+ }
- Json::Value minorValue = requestedProtocolVersion["minor"];
- if (!minorValue.isNull() && !minorValue.isInt())
- return request.ReportError("\"minor\" must be unset or an integer.");
+ Json::Value minorValue = requestedProtocolVersion[kMINOR_KEY];
+ if (!minorValue.isNull() && !minorValue.isInt()) {
+ return request.ReportError("\"" + kMINOR_KEY +
+ "\" must be unset or an integer.");
+ }
const int major = majorValue.asInt();
const int minor = minorValue.isNull() ? -1 : minorValue.asInt();
- if (major < 0)
- return request.ReportError("\"major\" must be >= 0.");
- if (!minorValue.isNull() && minor < 0)
- return request.ReportError("\"minor\" must be >= 0 when set.");
+ if (major < 0) {
+ return request.ReportError("\"" + kMAJOR_KEY + "\" must be >= 0.");
+ }
+ if (!minorValue.isNull() && minor < 0) {
+ return request.ReportError("\"" + kMINOR_KEY +
+ "\" must be >= 0 when set.");
+ }
this->Protocol =
this->FindMatchingProtocol(this->SupportedProtocols, major, minor);
@@ -226,7 +228,7 @@ cmServerResponse cmServer::SetProtocolVersion(const cmServerRequest& request)
}
std::string errorMessage;
- if (!this->Protocol->Activate(request, &errorMessage)) {
+ if (!this->Protocol->Activate(this, request, &errorMessage)) {
this->Protocol = CM_NULLPTR;
return request.ReportError("Failed to activate protocol version: " +
errorMessage);
@@ -290,12 +292,15 @@ cmServerProtocol* cmServer::FindMatchingProtocol(
cmServerProtocol* bestMatch = nullptr;
for (auto protocol : protocols) {
auto version = protocol->ProtocolVersion();
- if (major != version.first)
+ if (major != version.first) {
continue;
- if (minor == version.second)
+ }
+ if (minor == version.second) {
return protocol;
- if (!bestMatch || bestMatch->ProtocolVersion().second < version.second)
+ }
+ if (!bestMatch || bestMatch->ProtocolVersion().second < version.second) {
bestMatch = protocol;
+ }
}
return minor < 0 ? bestMatch : nullptr;
}
@@ -311,10 +316,10 @@ void cmServer::WriteProgress(const cmServerRequest& request, int min,
obj[kTYPE_KEY] = kPROGRESS_TYPE;
obj[kREPLY_TO_KEY] = request.Type;
obj[kCOOKIE_KEY] = request.Cookie;
- obj["progressMessage"] = message;
- obj["progressMinimum"] = min;
- obj["progressMaximum"] = max;
- obj["progressCurrent"] = current;
+ obj[kPROGRESS_MESSAGE_KEY] = message;
+ obj[kPROGRESS_MINIMUM_KEY] = min;
+ obj[kPROGRESS_MAXIMUM_KEY] = max;
+ obj[kPROGRESS_CURRENT_KEY] = current;
this->WriteJsonObject(obj, nullptr);
}
@@ -323,16 +328,17 @@ void cmServer::WriteMessage(const cmServerRequest& request,
const std::string& message,
const std::string& title) const
{
- if (message.empty())
+ if (message.empty()) {
return;
+ }
Json::Value obj = Json::objectValue;
obj[kTYPE_KEY] = kMESSAGE_TYPE;
obj[kREPLY_TO_KEY] = request.Type;
obj[kCOOKIE_KEY] = request.Cookie;
- obj["message"] = message;
+ obj[kMESSAGE_KEY] = message;
if (!title.empty()) {
- obj["title"] = title;
+ obj[kTITLE_KEY] = title;
}
WriteJsonObject(obj, nullptr);
@@ -349,6 +355,19 @@ void cmServer::WriteParseError(const std::string& message) const
this->WriteJsonObject(obj, nullptr);
}
+void cmServer::WriteSignal(const std::string& name,
+ const Json::Value& data) const
+{
+ assert(data.isObject());
+ Json::Value obj = data;
+ obj[kTYPE_KEY] = kSIGNAL_TYPE;
+ obj[kREPLY_TO_KEY] = "";
+ obj[kCOOKIE_KEY] = "";
+ obj[kNAME_KEY] = name;
+
+ WriteJsonObject(obj, nullptr);
+}
+
void cmServer::WriteResponse(const cmServerResponse& response,
const DebugInfo* debug) const
{
diff --git a/Source/cmServer.h b/Source/cmServer.h
index dde5333..849e5c5 100644
--- a/Source/cmServer.h
+++ b/Source/cmServer.h
@@ -63,6 +63,7 @@ private:
void WriteResponse(const cmServerResponse& response,
const DebugInfo* debug) const;
void WriteParseError(const std::string& message) const;
+ void WriteSignal(const std::string& name, const Json::Value& obj) const;
void WriteJsonObject(Json::Value const& jsonValue,
const DebugInfo* debug) const;
@@ -95,6 +96,7 @@ private:
mutable bool Writing = false;
- friend class cmServerRequest;
friend class cmServerConnection;
+ friend class cmServerProtocol;
+ friend class cmServerRequest;
};
diff --git a/Source/cmServerConnection.cxx b/Source/cmServerConnection.cxx
index 398e250..0b3db9f 100644
--- a/Source/cmServerConnection.cxx
+++ b/Source/cmServerConnection.cxx
@@ -13,15 +13,14 @@
#include "cmServerConnection.h"
+#include "cmServerDictionary.h"
+
#include <cmServer.h>
#include <assert.h>
namespace {
-static const std::string kSTART_MAGIC = "[== CMake Server ==[";
-static const std::string kEND_MAGIC = "]== CMake Server ==]";
-
struct write_req_t
{
uv_write_t req;
@@ -147,8 +146,9 @@ void cmServerConnection::ReadData(const std::string& data)
}
std::string line = this->RawReadBuffer.substr(0, needle);
const auto ls = line.size();
- if (ls > 1 && line.at(ls - 1) == '\r')
+ if (ls > 1 && line.at(ls - 1) == '\r') {
line.erase(ls - 1, 1);
+ }
this->RawReadBuffer.erase(this->RawReadBuffer.begin(),
this->RawReadBuffer.begin() +
static_cast<long>(needle) + 1);
diff --git a/Source/cmServerDictionary.h b/Source/cmServerDictionary.h
new file mode 100644
index 0000000..fc1b44d
--- /dev/null
+++ b/Source/cmServerDictionary.h
@@ -0,0 +1,62 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2016 Tobias Hunger <tobias.hunger@qt.io>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#pragma once
+
+#include <string>
+
+// Vocabulary:
+
+static const std::string kCOMPUTE_TYPE = "compute";
+static const std::string kCONFIGURE_TYPE = "configure";
+static const std::string kERROR_TYPE = "error";
+static const std::string kGLOBAL_SETTINGS_TYPE = "globalSettings";
+static const std::string kHANDSHAKE_TYPE = "handshake";
+static const std::string kMESSAGE_TYPE = "message";
+static const std::string kPROGRESS_TYPE = "progress";
+static const std::string kREPLY_TYPE = "reply";
+static const std::string kSET_GLOBAL_SETTINGS_TYPE = "setGlobalSettings";
+static const std::string kSIGNAL_TYPE = "signal";
+
+static const std::string kBUILD_DIRECTORY_KEY = "buildDirectory";
+static const std::string kCACHE_ARGUMENTS_KEY = "cacheArguments";
+static const std::string kCAPABILITIES_KEY = "capabilities";
+static const std::string kCHECK_SYSTEM_VARS_KEY = "checkSystemVars";
+static const std::string kCOOKIE_KEY = "cookie";
+static const std::string kDEBUG_OUTPUT_KEY = "debugOutput";
+static const std::string kERROR_MESSAGE_KEY = "errorMessage";
+static const std::string kEXTRA_GENERATOR_KEY = "extraGenerator";
+static const std::string kGENERATOR_KEY = "generator";
+static const std::string kIS_EXPERIMENTAL_KEY = "isExperimental";
+static const std::string kMAJOR_KEY = "major";
+static const std::string kMESSAGE_KEY = "message";
+static const std::string kMINOR_KEY = "minor";
+static const std::string kNAME_KEY = "name";
+static const std::string kPROGRESS_CURRENT_KEY = "progressCurrent";
+static const std::string kPROGRESS_MAXIMUM_KEY = "progressMaximum";
+static const std::string kPROGRESS_MESSAGE_KEY = "progressMessage";
+static const std::string kPROGRESS_MINIMUM_KEY = "progressMinimum";
+static const std::string kPROTOCOL_VERSION_KEY = "protocolVersion";
+static const std::string kREPLY_TO_KEY = "inReplyTo";
+static const std::string kSOURCE_DIRECTORY_KEY = "sourceDirectory";
+static const std::string kSUPPORTED_PROTOCOL_VERSIONS =
+ "supportedProtocolVersions";
+static const std::string kTITLE_KEY = "title";
+static const std::string kTRACE_EXPAND_KEY = "traceExpand";
+static const std::string kTRACE_KEY = "trace";
+static const std::string kTYPE_KEY = "type";
+static const std::string kWARN_UNINITIALIZED_KEY = "warnUninitialized";
+static const std::string kWARN_UNUSED_CLI_KEY = "warnUnusedCli";
+static const std::string kWARN_UNUSED_KEY = "warnUnused";
+
+static const std::string kSTART_MAGIC = "[== CMake Server ==[";
+static const std::string kEND_MAGIC = "]== CMake Server ==]";
diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx
index 26942d3..134edf3 100644
--- a/Source/cmServerProtocol.cxx
+++ b/Source/cmServerProtocol.cxx
@@ -13,24 +13,19 @@
#include "cmServerProtocol.h"
#include "cmExternalMakefileProjectGenerator.h"
+#include "cmGlobalGenerator.h"
#include "cmServer.h"
+#include "cmServerDictionary.h"
#include "cmSystemTools.h"
#include "cmake.h"
+#include "cmServerDictionary.h"
+
#if defined(CMAKE_BUILD_WITH_CMAKE)
#include "cm_jsoncpp_reader.h"
#include "cm_jsoncpp_value.h"
#endif
-// Vocabulary:
-
-static const std::string kBUILD_DIRECTORY_KEY = "buildDirectory";
-static const std::string kCOOKIE_KEY = "cookie";
-static const std::string kEXTRA_GENERATOR_KEY = "extraGenerator";
-static const std::string kGENERATOR_KEY = "generator";
-static const std::string kSOURCE_DIRECTORY_KEY = "sourceDirectory";
-static const std::string kTYPE_KEY = "type";
-
cmServerRequest::cmServerRequest(cmServer* server, const std::string& t,
const std::string& c, const Json::Value& d)
: Type(t)
@@ -103,10 +98,10 @@ bool cmServerResponse::IsError() const
std::string cmServerResponse::ErrorMessage() const
{
- if (this->m_Payload == PAYLOAD_ERROR)
+ if (this->m_Payload == PAYLOAD_ERROR) {
return this->m_ErrorMessage;
- else
- return std::string();
+ }
+ return std::string();
}
Json::Value cmServerResponse::Data() const
@@ -115,16 +110,28 @@ Json::Value cmServerResponse::Data() const
return this->m_Data;
}
-bool cmServerProtocol::Activate(const cmServerRequest& request,
+bool cmServerProtocol::Activate(cmServer* server,
+ const cmServerRequest& request,
std::string* errorMessage)
{
+ assert(server);
+ this->m_Server = server;
this->m_CMakeInstance = std::make_unique<cmake>();
const bool result = this->DoActivate(request, errorMessage);
- if (!result)
+ if (!result) {
this->m_CMakeInstance = CM_NULLPTR;
+ }
return result;
}
+void cmServerProtocol::SendSignal(const std::string& name,
+ const Json::Value& data) const
+{
+ if (this->m_Server) {
+ this->m_Server->WriteSignal(name, data);
+ }
+}
+
cmake* cmServerProtocol::CMakeInstance() const
{
return this->m_CMakeInstance.get();
@@ -151,17 +158,19 @@ bool cmServerProtocol1_0::DoActivate(const cmServerRequest& request,
std::string extraGenerator = request.Data[kEXTRA_GENERATOR_KEY].asString();
if (buildDirectory.empty()) {
- if (errorMessage)
+ if (errorMessage) {
*errorMessage =
std::string("\"") + kBUILD_DIRECTORY_KEY + "\" is missing.";
+ }
return false;
}
cmake* cm = CMakeInstance();
if (cmSystemTools::PathExists(buildDirectory)) {
if (!cmSystemTools::FileIsDirectory(buildDirectory)) {
- if (errorMessage)
+ if (errorMessage) {
*errorMessage = std::string("\"") + kBUILD_DIRECTORY_KEY +
"\" exists but is not a directory.";
+ }
return false;
}
@@ -173,18 +182,20 @@ bool cmServerProtocol1_0::DoActivate(const cmServerRequest& request,
const std::string cachedGenerator =
std::string(state->GetCacheEntryValue("CMAKE_GENERATOR"));
if (cachedGenerator.empty() && generator.empty()) {
- if (errorMessage)
+ if (errorMessage) {
*errorMessage =
std::string("\"") + kGENERATOR_KEY + "\" is required but unset.";
+ }
return false;
}
if (generator.empty()) {
generator = cachedGenerator;
}
if (generator != cachedGenerator) {
- if (errorMessage)
+ if (errorMessage) {
*errorMessage = std::string("\"") + kGENERATOR_KEY +
"\" set but incompatible with configured generator.";
+ }
return false;
}
@@ -193,9 +204,10 @@ bool cmServerProtocol1_0::DoActivate(const cmServerRequest& request,
std::string(state->GetCacheEntryValue("CMAKE_EXTRA_GENERATOR"));
if (!cachedExtraGenerator.empty() && !extraGenerator.empty() &&
cachedExtraGenerator != extraGenerator) {
- if (errorMessage)
+ if (errorMessage) {
*errorMessage = std::string("\"") + kEXTRA_GENERATOR_KEY +
"\" is set but incompatible with configured extra generator.";
+ }
return false;
}
if (extraGenerator.empty()) {
@@ -207,9 +219,10 @@ bool cmServerProtocol1_0::DoActivate(const cmServerRequest& request,
std::string(state->GetCacheEntryValue("CMAKE_HOME_DIRECTORY"));
if (!cachedSourceDirectory.empty() && !sourceDirectory.empty() &&
cachedSourceDirectory != sourceDirectory) {
- if (errorMessage)
+ if (errorMessage) {
*errorMessage = std::string("\"") + kSOURCE_DIRECTORY_KEY +
"\" is set but incompatible with configured source directory.";
+ }
return false;
}
if (sourceDirectory.empty()) {
@@ -219,21 +232,24 @@ bool cmServerProtocol1_0::DoActivate(const cmServerRequest& request,
}
if (sourceDirectory.empty()) {
- if (errorMessage)
+ if (errorMessage) {
*errorMessage = std::string("\"") + kSOURCE_DIRECTORY_KEY +
"\" is unset but required.";
+ }
return false;
}
if (!cmSystemTools::FileIsDirectory(sourceDirectory)) {
- if (errorMessage)
+ if (errorMessage) {
*errorMessage =
std::string("\"") + kSOURCE_DIRECTORY_KEY + "\" is not a directory.";
+ }
return false;
}
if (generator.empty()) {
- if (errorMessage)
+ if (errorMessage) {
*errorMessage =
std::string("\"") + kGENERATOR_KEY + "\" is unset but required.";
+ }
return false;
}
@@ -243,10 +259,11 @@ bool cmServerProtocol1_0::DoActivate(const cmServerRequest& request,
cmGlobalGenerator* gg = cm->CreateGlobalGenerator(fullGeneratorName);
if (!gg) {
- if (errorMessage)
+ if (errorMessage) {
*errorMessage =
std::string("Could not set up the requested combination of \"") +
kGENERATOR_KEY + "\" and \"" + kEXTRA_GENERATOR_KEY + "\"";
+ }
return false;
}
@@ -263,6 +280,19 @@ const cmServerResponse cmServerProtocol1_0::Process(
{
assert(this->m_State >= STATE_ACTIVE);
+ if (request.Type == kCOMPUTE_TYPE) {
+ return this->ProcessCompute(request);
+ }
+ if (request.Type == kCONFIGURE_TYPE) {
+ return this->ProcessConfigure(request);
+ }
+ if (request.Type == kGLOBAL_SETTINGS_TYPE) {
+ return this->ProcessGlobalSettings(request);
+ }
+ if (request.Type == kSET_GLOBAL_SETTINGS_TYPE) {
+ return this->ProcessSetGlobalSettings(request);
+ }
+
return request.ReportError("Unknown command!");
}
@@ -270,3 +300,179 @@ bool cmServerProtocol1_0::IsExperimental() const
{
return true;
}
+
+cmServerResponse cmServerProtocol1_0::ProcessCompute(
+ const cmServerRequest& request)
+{
+ if (this->m_State > STATE_CONFIGURED) {
+ return request.ReportError("This build system was already generated.");
+ }
+ if (this->m_State < STATE_CONFIGURED) {
+ return request.ReportError("This project was not configured yet.");
+ }
+
+ cmake* cm = this->CMakeInstance();
+ int ret = cm->Generate();
+
+ if (ret < 0) {
+ return request.ReportError("Failed to compute build system.");
+ }
+ m_State = STATE_COMPUTED;
+ return request.Reply(Json::Value());
+}
+
+cmServerResponse cmServerProtocol1_0::ProcessConfigure(
+ const cmServerRequest& request)
+{
+ if (this->m_State == STATE_INACTIVE) {
+ return request.ReportError("This instance is inactive.");
+ }
+
+ // Make sure the types of cacheArguments matches (if given):
+ std::vector<std::string> cacheArgs;
+ bool cacheArgumentsError = false;
+ const Json::Value passedArgs = request.Data[kCACHE_ARGUMENTS_KEY];
+ if (!passedArgs.isNull()) {
+ if (passedArgs.isString()) {
+ cacheArgs.push_back(passedArgs.asString());
+ } else if (passedArgs.isArray()) {
+ for (auto i = passedArgs.begin(); i != passedArgs.end(); ++i) {
+ if (!i->isString()) {
+ cacheArgumentsError = true;
+ break;
+ }
+ cacheArgs.push_back(i->asString());
+ }
+ } else {
+ cacheArgumentsError = true;
+ }
+ }
+ if (cacheArgumentsError) {
+ request.ReportError(
+ "cacheArguments must be unset, a string or an array of strings.");
+ }
+
+ cmake* cm = this->CMakeInstance();
+ std::string sourceDir = cm->GetHomeDirectory();
+ const std::string buildDir = cm->GetHomeOutputDirectory();
+
+ if (buildDir.empty()) {
+ return request.ReportError(
+ "No build directory set via setGlobalSettings.");
+ }
+
+ if (cm->LoadCache(buildDir)) {
+ // build directory has been set up before
+ const char* cachedSourceDir =
+ cm->GetState()->GetInitializedCacheValue("CMAKE_HOME_DIRECTORY");
+ if (!cachedSourceDir) {
+ return request.ReportError("No CMAKE_HOME_DIRECTORY found in cache.");
+ }
+ if (sourceDir.empty()) {
+ sourceDir = std::string(cachedSourceDir);
+ cm->SetHomeDirectory(sourceDir);
+ }
+
+ const char* cachedGenerator =
+ cm->GetState()->GetInitializedCacheValue("CMAKE_GENERATOR");
+ if (cachedGenerator) {
+ cmGlobalGenerator* gen = cm->GetGlobalGenerator();
+ if (gen && gen->GetName() != cachedGenerator) {
+ return request.ReportError("Configured generator does not match with "
+ "CMAKE_GENERATOR found in cache.");
+ }
+ }
+ } else {
+ // build directory has not been set up before
+ if (sourceDir.empty()) {
+ return request.ReportError("No sourceDirectory set via "
+ "setGlobalSettings and no cache found in "
+ "buildDirectory.");
+ }
+ }
+
+ if (cm->AddCMakePaths() != 1) {
+ return request.ReportError("Failed to set CMake paths.");
+ }
+
+ if (!cm->SetCacheArgs(cacheArgs)) {
+ return request.ReportError("cacheArguments could not be set.");
+ }
+
+ int ret = cm->Configure();
+ if (ret < 0) {
+ return request.ReportError("Configuration failed.");
+ }
+ m_State = STATE_CONFIGURED;
+ return request.Reply(Json::Value());
+}
+
+cmServerResponse cmServerProtocol1_0::ProcessGlobalSettings(
+ const cmServerRequest& request)
+{
+ cmake* cm = this->CMakeInstance();
+ Json::Value obj = Json::objectValue;
+
+ // Capabilities information:
+ obj[kCAPABILITIES_KEY] = cm->ReportCapabilitiesJson(true);
+
+ obj[kDEBUG_OUTPUT_KEY] = cm->GetDebugOutput();
+ obj[kTRACE_KEY] = cm->GetTrace();
+ obj[kTRACE_EXPAND_KEY] = cm->GetTraceExpand();
+ obj[kWARN_UNINITIALIZED_KEY] = cm->GetWarnUninitialized();
+ obj[kWARN_UNUSED_KEY] = cm->GetWarnUnused();
+ obj[kWARN_UNUSED_CLI_KEY] = cm->GetWarnUnusedCli();
+ obj[kCHECK_SYSTEM_VARS_KEY] = cm->GetCheckSystemVars();
+
+ obj[kSOURCE_DIRECTORY_KEY] = cm->GetHomeDirectory();
+ obj[kBUILD_DIRECTORY_KEY] = cm->GetHomeOutputDirectory();
+
+ // Currently used generator:
+ cmGlobalGenerator* gen = cm->GetGlobalGenerator();
+ obj[kGENERATOR_KEY] = gen ? gen->GetName() : std::string();
+ obj[kEXTRA_GENERATOR_KEY] =
+ gen ? gen->GetExtraGeneratorName() : std::string();
+
+ return request.Reply(obj);
+}
+
+static void setBool(const cmServerRequest& request, const std::string& key,
+ std::function<void(bool)> setter)
+{
+ if (request.Data[key].isNull()) {
+ return;
+ }
+ setter(request.Data[key].asBool());
+}
+
+cmServerResponse cmServerProtocol1_0::ProcessSetGlobalSettings(
+ const cmServerRequest& request)
+{
+ const std::vector<std::string> boolValues = {
+ kDEBUG_OUTPUT_KEY, kTRACE_KEY, kTRACE_EXPAND_KEY,
+ kWARN_UNINITIALIZED_KEY, kWARN_UNUSED_KEY, kWARN_UNUSED_CLI_KEY,
+ kCHECK_SYSTEM_VARS_KEY
+ };
+ for (auto i : boolValues) {
+ if (!request.Data[i].isNull() && !request.Data[i].isBool()) {
+ return request.ReportError("\"" + i +
+ "\" must be unset or a bool value.");
+ }
+ }
+
+ cmake* cm = this->CMakeInstance();
+
+ setBool(request, kDEBUG_OUTPUT_KEY,
+ [cm](bool e) { cm->SetDebugOutputOn(e); });
+ setBool(request, kTRACE_KEY, [cm](bool e) { cm->SetTrace(e); });
+ setBool(request, kTRACE_EXPAND_KEY, [cm](bool e) { cm->SetTraceExpand(e); });
+ setBool(request, kWARN_UNINITIALIZED_KEY,
+ [cm](bool e) { cm->SetWarnUninitialized(e); });
+ setBool(request, kWARN_UNUSED_KEY, [cm](bool e) { cm->SetWarnUnused(e); });
+ setBool(request, kWARN_UNUSED_CLI_KEY,
+ [cm](bool e) { cm->SetWarnUnusedCli(e); });
+ setBool(request, kCHECK_SYSTEM_VARS_KEY,
+ [cm](bool e) { cm->SetCheckSystemVars(e); });
+
+ return request.Reply(Json::Value());
+}
diff --git a/Source/cmServerProtocol.h b/Source/cmServerProtocol.h
index bab949b..e772eca 100644
--- a/Source/cmServerProtocol.h
+++ b/Source/cmServerProtocol.h
@@ -13,6 +13,7 @@
#pragma once
#include "cmListFileCache.h"
+#include "cmake.h"
#if defined(CMAKE_BUILD_WITH_CMAKE)
#include "cm_jsoncpp_writer.h"
@@ -87,7 +88,10 @@ public:
virtual bool IsExperimental() const = 0;
virtual const cmServerResponse Process(const cmServerRequest& request) = 0;
- bool Activate(const cmServerRequest& request, std::string* errorMessage);
+ bool Activate(cmServer* server, const cmServerRequest& request,
+ std::string* errorMessage);
+
+ void SendSignal(const std::string& name, const Json::Value& data) const;
protected:
cmake* CMakeInstance() const;
@@ -97,6 +101,7 @@ protected:
private:
std::unique_ptr<cmake> m_CMakeInstance;
+ cmServer* m_Server = nullptr; // not owned!
friend class cmServer;
};
@@ -112,10 +117,18 @@ private:
bool DoActivate(const cmServerRequest& request,
std::string* errorMessage) override;
+ // Handle requests:
+ cmServerResponse ProcessCompute(const cmServerRequest& request);
+ cmServerResponse ProcessConfigure(const cmServerRequest& request);
+ cmServerResponse ProcessGlobalSettings(const cmServerRequest& request);
+ cmServerResponse ProcessSetGlobalSettings(const cmServerRequest& request);
+
enum State
{
STATE_INACTIVE,
- STATE_ACTIVE
+ STATE_ACTIVE,
+ STATE_CONFIGURED,
+ STATE_COMPUTED
};
State m_State = STATE_INACTIVE;
};
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 1dad742..eb17561 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -1164,7 +1164,8 @@ const char* cmTarget::GetProperty(const std::string& prop,
}
}
// Support "<CONFIG>_LOCATION".
- else if (cmHasLiteralSuffix(prop, "_LOCATION")) {
+ else if (cmHasLiteralSuffix(prop, "_LOCATION") &&
+ !cmHasLiteralPrefix(prop, "XCODE_ATTRIBUTE_")) {
std::string configName(prop.c_str(), prop.size() - 9);
if (configName != "IMPORTED") {
if (!this->HandleLocationPropertyPolicy(context)) {
diff --git a/Source/cm_auto_ptr.hxx b/Source/cm_auto_ptr.hxx
index f6c4362..f38eda5 100644
--- a/Source/cm_auto_ptr.hxx
+++ b/Source/cm_auto_ptr.hxx
@@ -14,7 +14,13 @@
#include <cmConfigure.h>
-// FIXME: Use std::auto_ptr on compilers that do not warn about it.
+#ifdef CMake_HAVE_CXX_AUTO_PTR
+
+#include <memory>
+#define CM_AUTO_PTR std::auto_ptr
+
+#else
+
#define CM_AUTO_PTR cm::auto_ptr
// The HP compiler cannot handle the conversions necessary to use
@@ -219,3 +225,5 @@ public:
#endif
#endif
+
+#endif
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 9daed4b..2b4a830 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -52,6 +52,11 @@
#include <stdlib.h>
#include <time.h>
+int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
+ std::vector<std::string>::const_iterator argEnd);
+int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
+ std::vector<std::string>::const_iterator argEnd);
+
void CMakeCommandUsage(const char* program)
{
std::ostringstream errorStream;
@@ -782,6 +787,18 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
return cmcmd::ExecuteLinkScript(args);
}
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ // Internal CMake ninja dependency scanning support.
+ else if (args[1] == "cmake_ninja_depends") {
+ return cmcmd_cmake_ninja_depends(args.begin() + 2, args.end());
+ }
+
+ // Internal CMake ninja dyndep support.
+ else if (args[1] == "cmake_ninja_dyndep") {
+ return cmcmd_cmake_ninja_dyndep(args.begin() + 2, args.end());
+ }
+#endif
+
// Internal CMake unimplemented feature notification.
else if (args[1] == "cmake_unimplemented_variable") {
std::cerr << "Feature not implemented for this platform.";
diff --git a/Source/kwsys/testConsoleBuf.cxx b/Source/kwsys/testConsoleBuf.cxx
index 3dc3337..d7775e6 100644
--- a/Source/kwsys/testConsoleBuf.cxx
+++ b/Source/kwsys/testConsoleBuf.cxx
@@ -103,7 +103,7 @@ static void dumpBuffers(const T *expected, const T *received, size_t size) {
}
std::cerr << std::endl;
}
- std::cerr << std::endl << std::flush;
+ std::cerr << std::endl;
}
//----------------------------------------------------------------------------
@@ -331,21 +331,23 @@ static int testPipe()
didFail = encodedTestString.compare(buffer2) == 0 ? 0 : 1;
}
if (didFail != 0) {
- std::cerr << "Pipe's output didn't match expected output!" << std::endl << std::flush;
+ std::cerr << "Pipe's output didn't match expected output!" << std::endl;
dumpBuffers<char>(encodedTestString.c_str(), buffer, encodedTestString.size());
dumpBuffers<char>(encodedInputTestString.c_str(), buffer + encodedTestString.size() + 1, encodedInputTestString.size());
dumpBuffers<char>(encodedTestString.c_str(), buffer2, encodedTestString.size());
}
} catch (const std::runtime_error &ex) {
DWORD lastError = GetLastError();
- std::cerr << "In function " << __FUNCTION__ << ":" << ex.what() << std::endl << std::flush;
+ std::cerr << "In function testPipe, line " << __LINE__ << ": "
+ << ex.what() << std::endl;
displayError(lastError);
}
finishProcess(didFail == 0);
}
} catch (const std::runtime_error &ex) {
DWORD lastError = GetLastError();
- std::cerr << "In function " << __FUNCTION__ << ":" << ex.what() << std::endl << std::flush;
+ std::cerr << "In function testPipe, line " << __LINE__ << ": "
+ << ex.what() << std::endl;
displayError(lastError);
}
finishPipe(inPipeRead, inPipeWrite);
@@ -368,11 +370,11 @@ static int testFile()
(errFile = createFile(L"stderrFile.txt")) == INVALID_HANDLE_VALUE) {
throw std::runtime_error("createFile failed!");
}
- int length = 0;
DWORD bytesWritten = 0;
char buffer[200];
char buffer2[200];
+ int length;
if ((length = WideCharToMultiByte(TestCodepage, 0, UnicodeInputTestString, -1,
buffer, sizeof(buffer),
NULL, NULL)) == 0) {
@@ -424,21 +426,23 @@ static int testFile()
didFail = encodedTestString.compare(buffer2) == 0 ? 0 : 1;
}
if (didFail != 0) {
- std::cerr << "File's output didn't match expected output!" << std::endl << std::flush;
+ std::cerr << "File's output didn't match expected output!" << std::endl;
dumpBuffers<char>(encodedTestString.c_str(), buffer, encodedTestString.size());
dumpBuffers<char>(encodedInputTestString.c_str(), buffer + encodedTestString.size() + 1, encodedInputTestString.size() - 1);
dumpBuffers<char>(encodedTestString.c_str(), buffer2, encodedTestString.size());
}
} catch (const std::runtime_error &ex) {
DWORD lastError = GetLastError();
- std::cerr << "In function " << __FUNCTION__ << ":" << ex.what() << std::endl << std::flush;
+ std::cerr << "In function testFile, line " << __LINE__ << ": "
+ << ex.what() << std::endl;
displayError(lastError);
}
finishProcess(didFail == 0);
}
} catch (const std::runtime_error &ex) {
DWORD lastError = GetLastError();
- std::cerr << "In function " << __FUNCTION__ << ":" << ex.what() << std::endl << std::flush;
+ std::cerr << "In function testFile, line " << __LINE__ << ": "
+ << ex.what() << std::endl;
displayError(lastError);
}
finishFile(inFile);
@@ -508,18 +512,18 @@ static int testConsole()
forceNewConsole = true;
}
} else {
- std::cerr << "RegGetValueW(FontFamily) failed!" << std::endl << std::flush;
+ std::cerr << "RegGetValueW(FontFamily) failed!" << std::endl;
}
RegCloseKey(hConsoleKey);
} else {
- std::cerr << "RegOpenKeyExW(HKEY_CURRENT_USER\\Console) failed!" << std::endl << std::flush;
+ std::cerr << "RegOpenKeyExW(HKEY_CURRENT_USER\\Console) failed!" << std::endl;
}
}
if (forceNewConsole || GetConsoleMode(parentOut, &consoleMode) == 0) {
// Not a real console, let's create new one.
FreeConsole();
if (!AllocConsole()) {
- std::cerr << "AllocConsole failed!" << std::endl << std::flush;
+ std::cerr << "AllocConsole failed!" << std::endl;
return didFail;
}
SECURITY_ATTRIBUTES securityAttributes;
@@ -561,11 +565,11 @@ static int testConsole()
consoleFont.FontFamily = TestFontFamily;
wcscpy(consoleFont.FaceName, TestFaceName);
if (!setConsoleFont(hOut, FALSE, &consoleFont)) {
- std::cerr << "SetCurrentConsoleFontEx failed!" << std::endl << std::flush;
+ std::cerr << "SetCurrentConsoleFontEx failed!" << std::endl;
}
}
} else {
- std::cerr << "GetCurrentConsoleFontEx failed!" << std::endl << std::flush;
+ std::cerr << "GetCurrentConsoleFontEx failed!" << std::endl;
}
} else {
#endif
@@ -599,7 +603,7 @@ static int testConsole()
INPUT_RECORD inputBuffer[(sizeof(UnicodeInputTestString) /
sizeof(UnicodeInputTestString[0])) * 2];
memset(&inputBuffer, 0, sizeof(inputBuffer));
- unsigned int i = 0;
+ unsigned int i;
for (i = 0; i < (sizeof(UnicodeInputTestString) /
sizeof(UnicodeInputTestString[0]) - 1); i++) {
writeInputKeyEvent(&inputBuffer[i*2], UnicodeInputTestString[i]);
@@ -650,7 +654,7 @@ static int testConsole()
) {
didFail = 0;
} else {
- std::cerr << "Console's output didn't match expected output!" << std::endl << std::flush;
+ std::cerr << "Console's output didn't match expected output!" << std::endl;
dumpBuffers<wchar_t>(wideTestString.c_str(), outputBuffer, wideTestString.size());
dumpBuffers<wchar_t>(wideTestString.c_str(), outputBuffer + screenBufferInfo.dwSize.X * 1, wideTestString.size());
dumpBuffers<wchar_t>(UnicodeInputTestString, outputBuffer + screenBufferInfo.dwSize.X * 2, (sizeof(UnicodeInputTestString) - 1) / sizeof(WCHAR));
@@ -659,7 +663,8 @@ static int testConsole()
delete[] outputBuffer;
} catch (const std::runtime_error &ex) {
DWORD lastError = GetLastError();
- std::cerr << "In function " << __FUNCTION__ << ":" << ex.what() << std::endl << std::flush;
+ std::cerr << "In function testConsole, line " << __LINE__ << ": "
+ << ex.what() << std::endl;
displayError(lastError);
}
finishProcess(didFail == 0);