Merge topic 'ninja-fortran'
33058150
Help: Document Ninja generator conditional Fortran support59aae292
Ninja: Add dyndep rules for Fortran module dependencies39ebfc79
Ninja: Add explicit preprocessing step for Fortran9a77680e
Ninja: Conditionally allow Fortran based on ninja 'dyndep' support0f331d78
Ninja: Add internal tool to produce a ninja dyndep file for Fortrand3e0b64b
Ninja: Add internal tool to scan Fortran code for module dependencies8eca59a1
Ninja: Add comment with Fortran dependency design documentationa57d1bb7
Ninja: Add API to check for dyndep support0488ae63
Ninja: Refactor ninja feature detectionf0a23aa3
Ninja: Refactor Fortran rejection logic
This commit is contained in:
commit
3a883a9f7d
|
@ -21,3 +21,13 @@ are generated:
|
||||||
|
|
||||||
``sub/dir/package``
|
``sub/dir/package``
|
||||||
Runs the package step in the subdirectory, if any.
|
Runs the package step in the subdirectory, if any.
|
||||||
|
|
||||||
|
Fortran Support
|
||||||
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
The ``Ninja`` generator conditionally supports Fortran when the ``ninja``
|
||||||
|
tool has the required features. As of this version of CMake the needed
|
||||||
|
features have not been integrated into upstream Ninja. Kitware maintains
|
||||||
|
a branch of Ninja with the required features on `github.com/Kitware/ninja`_.
|
||||||
|
|
||||||
|
.. _`github.com/Kitware/ninja`: https://github.com/Kitware/ninja/tree/features-for-fortran#readme
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
ninja-fortran
|
||||||
|
-------------
|
||||||
|
|
||||||
|
* The :generator:`Ninja` generator learned to conditionally support
|
||||||
|
Fortran when using a ``ninja`` tool that has the necessary features.
|
||||||
|
See generator documentation for details.
|
|
@ -1,6 +1,9 @@
|
||||||
include(Compiler/GNU)
|
include(Compiler/GNU)
|
||||||
__compiler_gnu(Fortran)
|
__compiler_gnu(Fortran)
|
||||||
|
|
||||||
|
set(CMAKE_Fortran_PREPROCESS_SOURCE
|
||||||
|
"<CMAKE_Fortran_COMPILER> -cpp <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> -o <PREPROCESSED_SOURCE>")
|
||||||
|
|
||||||
set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed-form")
|
set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed-form")
|
||||||
set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree-form")
|
set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree-form")
|
||||||
|
|
||||||
|
|
|
@ -7,3 +7,6 @@ set(CMAKE_Fortran_FORMAT_FREE_FLAG "-free")
|
||||||
|
|
||||||
set(CMAKE_Fortran_CREATE_PREPROCESSED_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
|
set(CMAKE_Fortran_CREATE_PREPROCESSED_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
|
||||||
set(CMAKE_Fortran_CREATE_ASSEMBLY_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
|
set(CMAKE_Fortran_CREATE_ASSEMBLY_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
|
||||||
|
|
||||||
|
set(CMAKE_Fortran_PREPROCESS_SOURCE
|
||||||
|
"<CMAKE_Fortran_COMPILER> -fpp <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
|
||||||
|
|
|
@ -18,5 +18,8 @@ string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT " -g -xO2 -DNDEBUG")
|
||||||
set(CMAKE_Fortran_MODDIR_FLAG "-moddir=")
|
set(CMAKE_Fortran_MODDIR_FLAG "-moddir=")
|
||||||
set(CMAKE_Fortran_MODPATH_FLAG "-M")
|
set(CMAKE_Fortran_MODPATH_FLAG "-M")
|
||||||
|
|
||||||
|
set(CMAKE_Fortran_PREPROCESS_SOURCE
|
||||||
|
"<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -F <SOURCE> -o <PREPROCESSED_SOURCE>")
|
||||||
|
|
||||||
set(CMAKE_Fortran_CREATE_PREPROCESSED_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -F <SOURCE> -o <PREPROCESSED_SOURCE>")
|
set(CMAKE_Fortran_CREATE_PREPROCESSED_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -F <SOURCE> -o <PREPROCESSED_SOURCE>")
|
||||||
set(CMAKE_Fortran_CREATE_ASSEMBLY_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
|
set(CMAKE_Fortran_CREATE_ASSEMBLY_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
|
||||||
|
|
|
@ -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
|
// enable the given language
|
||||||
//
|
//
|
||||||
// The following files are loaded in this order:
|
// The following files are loaded in this order:
|
||||||
|
@ -428,6 +434,10 @@ void cmGlobalGenerator::EnableLanguage(
|
||||||
// find and make sure CMAKE_MAKE_PROGRAM is defined
|
// find and make sure CMAKE_MAKE_PROGRAM is defined
|
||||||
this->FindMakeProgram(mf);
|
this->FindMakeProgram(mf);
|
||||||
|
|
||||||
|
if (!this->CheckLanguages(languages, mf)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// try and load the CMakeSystem.cmake if it is there
|
// try and load the CMakeSystem.cmake if it is there
|
||||||
std::string fpath = rootBin;
|
std::string fpath = rootBin;
|
||||||
bool const readCMakeSystem = !mf->GetDefinition("CMAKE_SYSTEM_LOADED");
|
bool const readCMakeSystem = !mf->GetDefinition("CMAKE_SYSTEM_LOADED");
|
||||||
|
|
|
@ -381,6 +381,8 @@ protected:
|
||||||
void SetLanguageEnabledFlag(const std::string& l, cmMakefile* mf);
|
void SetLanguageEnabledFlag(const std::string& l, cmMakefile* mf);
|
||||||
void SetLanguageEnabledMaps(const std::string& l, cmMakefile* mf);
|
void SetLanguageEnabledMaps(const std::string& l, cmMakefile* mf);
|
||||||
void FillExtensionToLanguageMap(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,
|
virtual void PrintCompilerAdvice(std::ostream& os, std::string const& lang,
|
||||||
const char* envVar) const;
|
const char* envVar) const;
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "cmAlgorithms.h"
|
#include "cmAlgorithms.h"
|
||||||
#include "cmDocumentationEntry.h"
|
#include "cmDocumentationEntry.h"
|
||||||
|
#include "cmFortranParser.h"
|
||||||
#include "cmGeneratedFileStream.h"
|
#include "cmGeneratedFileStream.h"
|
||||||
#include "cmGeneratorExpressionEvaluationFile.h"
|
#include "cmGeneratorExpressionEvaluationFile.h"
|
||||||
#include "cmGeneratorTarget.h"
|
#include "cmGeneratorTarget.h"
|
||||||
|
@ -26,8 +27,12 @@
|
||||||
#include "cmTarget.h"
|
#include "cmTarget.h"
|
||||||
#include "cmTargetDepend.h"
|
#include "cmTargetDepend.h"
|
||||||
#include "cmVersion.h"
|
#include "cmVersion.h"
|
||||||
|
#include "cm_auto_ptr.hxx"
|
||||||
#include "cmake.h"
|
#include "cmake.h"
|
||||||
|
|
||||||
|
#include "cm_jsoncpp_reader.h"
|
||||||
|
#include "cm_jsoncpp_writer.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
@ -473,6 +478,9 @@ cmGlobalNinjaGenerator::cmGlobalNinjaGenerator(cmake* cm)
|
||||||
, UsingGCCOnWindows(false)
|
, UsingGCCOnWindows(false)
|
||||||
, ComputingUnknownDependencies(false)
|
, ComputingUnknownDependencies(false)
|
||||||
, PolicyCMP0058(cmPolicies::WARN)
|
, PolicyCMP0058(cmPolicies::WARN)
|
||||||
|
, NinjaSupportsConsolePool(false)
|
||||||
|
, NinjaSupportsImplicitOuts(false)
|
||||||
|
, NinjaSupportsDyndeps(0)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
cm->GetState()->SetWindowsShell(true);
|
cm->GetState()->SetWindowsShell(true);
|
||||||
|
@ -558,15 +566,81 @@ void cmGlobalNinjaGenerator::FindMakeProgram(cmMakefile* mf)
|
||||||
cmSystemTools::RunSingleCommand(command, &version, CM_NULLPTR, CM_NULLPTR,
|
cmSystemTools::RunSingleCommand(command, &version, CM_NULLPTR, CM_NULLPTR,
|
||||||
CM_NULLPTR, cmSystemTools::OUTPUT_NONE);
|
CM_NULLPTR, cmSystemTools::OUTPUT_NONE);
|
||||||
this->NinjaVersion = cmSystemTools::TrimWhitespace(version);
|
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(
|
void cmGlobalNinjaGenerator::EnableLanguage(
|
||||||
std::vector<std::string> const& langs, cmMakefile* mf, bool optional)
|
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);
|
this->cmGlobalGenerator::EnableLanguage(langs, mf, optional);
|
||||||
for (std::vector<std::string>::const_iterator l = langs.begin();
|
for (std::vector<std::string>::const_iterator l = langs.begin();
|
||||||
l != langs.end(); ++l) {
|
l != langs.end(); ++l) {
|
||||||
|
@ -1301,16 +1375,12 @@ std::string cmGlobalNinjaGenerator::ninjaCmd() const
|
||||||
|
|
||||||
bool cmGlobalNinjaGenerator::SupportsConsolePool() const
|
bool cmGlobalNinjaGenerator::SupportsConsolePool() const
|
||||||
{
|
{
|
||||||
return !cmSystemTools::VersionCompare(
|
return this->NinjaSupportsConsolePool;
|
||||||
cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
|
|
||||||
RequiredNinjaVersionForConsolePool().c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cmGlobalNinjaGenerator::SupportsImplicitOuts() const
|
bool cmGlobalNinjaGenerator::SupportsImplicitOuts() const
|
||||||
{
|
{
|
||||||
return !cmSystemTools::VersionCompare(
|
return this->NinjaSupportsImplicitOuts;
|
||||||
cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
|
|
||||||
this->RequiredNinjaVersionForImplicitOuts().c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os)
|
void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os)
|
||||||
|
@ -1378,3 +1448,421 @@ void cmGlobalNinjaGenerator::StripNinjaOutputPathPrefixAsSuffix(
|
||||||
EnsureTrailingSlash(path);
|
EnsureTrailingSlash(path);
|
||||||
cmStripSuffixIfExists(path, this->OutputPathPrefix);
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -347,6 +347,15 @@ public:
|
||||||
bool HasOutputPathPrefix() const { return !this->OutputPathPrefix.empty(); }
|
bool HasOutputPathPrefix() const { return !this->OutputPathPrefix.empty(); }
|
||||||
void StripNinjaOutputPathPrefixAsSuffix(std::string& path);
|
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:
|
protected:
|
||||||
void Generate() CM_OVERRIDE;
|
void Generate() CM_OVERRIDE;
|
||||||
|
|
||||||
|
@ -355,6 +364,10 @@ protected:
|
||||||
private:
|
private:
|
||||||
std::string GetEditCacheCommand() const CM_OVERRIDE;
|
std::string GetEditCacheCommand() const CM_OVERRIDE;
|
||||||
void FindMakeProgram(cmMakefile* mf) 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 OpenBuildFileStream();
|
||||||
void CloseBuildFileStream();
|
void CloseBuildFileStream();
|
||||||
|
@ -439,6 +452,9 @@ private:
|
||||||
|
|
||||||
std::string NinjaCommand;
|
std::string NinjaCommand;
|
||||||
std::string NinjaVersion;
|
std::string NinjaVersion;
|
||||||
|
bool NinjaSupportsConsolePool;
|
||||||
|
bool NinjaSupportsImplicitOuts;
|
||||||
|
unsigned long NinjaSupportsDyndeps;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InitOutputPathPrefix();
|
void InitOutputPathPrefix();
|
||||||
|
|
|
@ -29,6 +29,8 @@
|
||||||
#include "cmSystemTools.h"
|
#include "cmSystemTools.h"
|
||||||
#include "cmake.h"
|
#include "cmake.h"
|
||||||
|
|
||||||
|
#include "cm_jsoncpp_writer.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
@ -93,6 +95,31 @@ std::string cmNinjaTargetGenerator::LanguageCompilerRule(
|
||||||
cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName());
|
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()
|
std::string cmNinjaTargetGenerator::OrderDependsTargetForTarget()
|
||||||
{
|
{
|
||||||
return "cmake_order_depends_target_" + this->GetTargetName();
|
return "cmake_order_depends_target_" + this->GetTargetName();
|
||||||
|
@ -229,6 +256,64 @@ std::string cmNinjaTargetGenerator::GetObjectFilePath(
|
||||||
return path;
|
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 cmNinjaTargetGenerator::GetTargetOutputDir() const
|
||||||
{
|
{
|
||||||
std::string dir = this->GeneratorTarget->GetDirectory(this->GetConfigName());
|
std::string dir = this->GeneratorTarget->GetDirectory(this->GetConfigName());
|
||||||
|
@ -311,6 +396,10 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
|
||||||
vars.ObjectDir = "$OBJECT_DIR";
|
vars.ObjectDir = "$OBJECT_DIR";
|
||||||
vars.ObjectFileDir = "$OBJECT_FILE_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();
|
cmMakefile* mf = this->GetMakefile();
|
||||||
|
|
||||||
std::string flags = "$FLAGS";
|
std::string flags = "$FLAGS";
|
||||||
|
@ -331,7 +420,9 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
|
||||||
std::string deptype;
|
std::string deptype;
|
||||||
std::string depfile;
|
std::string depfile;
|
||||||
std::string cldeps;
|
std::string cldeps;
|
||||||
if (this->NeedDepTypeMSVC(lang)) {
|
if (explicitPP) {
|
||||||
|
// The explicit preprocessing step will handle dependency scanning.
|
||||||
|
} else if (this->NeedDepTypeMSVC(lang)) {
|
||||||
deptype = "msvc";
|
deptype = "msvc";
|
||||||
depfile = "";
|
depfile = "";
|
||||||
flags += " /showIncludes";
|
flags += " /showIncludes";
|
||||||
|
@ -371,6 +462,109 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
|
||||||
vars.Flags = flags.c_str();
|
vars.Flags = flags.c_str();
|
||||||
vars.DependencyFile = depfile.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.
|
// Rule for compiling object file.
|
||||||
const std::string cmdVar = std::string("CMAKE_") + lang + "_COMPILE_OBJECT";
|
const std::string cmdVar = std::string("CMAKE_") + lang + "_COMPILE_OBJECT";
|
||||||
std::string compileCmd = mf->GetRequiredDefinition(cmdVar);
|
std::string compileCmd = mf->GetRequiredDefinition(cmdVar);
|
||||||
|
@ -519,6 +713,25 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements()
|
||||||
this->WriteObjectBuildStatement(*si, !orderOnlyDeps.empty());
|
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";
|
this->GetBuildFileStream() << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -589,6 +802,77 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
|
||||||
orderOnlyDeps);
|
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"];
|
||||||
|
|
||||||
|
// 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);
|
EnsureParentDirectoryExists(objectFileName);
|
||||||
|
|
||||||
vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
|
vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
|
||||||
|
@ -622,6 +906,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(
|
void cmNinjaTargetGenerator::ExportObjectCompileCommand(
|
||||||
std::string const& language, std::string const& sourceFileName,
|
std::string const& language, std::string const& sourceFileName,
|
||||||
std::string const& objectDir, std::string const& objectFileName,
|
std::string const& objectDir, std::string const& objectFileName,
|
||||||
|
|
|
@ -70,6 +70,10 @@ protected:
|
||||||
cmMakefile* GetMakefile() const { return this->Makefile; }
|
cmMakefile* GetMakefile() const { return this->Makefile; }
|
||||||
|
|
||||||
std::string LanguageCompilerRule(const std::string& lang) const;
|
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();
|
std::string OrderDependsTargetForTarget();
|
||||||
|
|
||||||
|
@ -107,6 +111,15 @@ protected:
|
||||||
/// @return the object file path for the given @a source.
|
/// @return the object file path for the given @a source.
|
||||||
std::string GetObjectFilePath(cmSourceFile const* source) const;
|
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.
|
/// @return the file path where the target named @a name is generated.
|
||||||
std::string GetTargetFilePath(const std::string& name) const;
|
std::string GetTargetFilePath(const std::string& name) const;
|
||||||
|
|
||||||
|
@ -118,6 +131,7 @@ protected:
|
||||||
void WriteObjectBuildStatements();
|
void WriteObjectBuildStatements();
|
||||||
void WriteObjectBuildStatement(cmSourceFile const* source,
|
void WriteObjectBuildStatement(cmSourceFile const* source,
|
||||||
bool writeOrderDependsTargetForTarget);
|
bool writeOrderDependsTargetForTarget);
|
||||||
|
void WriteTargetDependInfo(std::string const& lang);
|
||||||
|
|
||||||
void ExportObjectCompileCommand(
|
void ExportObjectCompileCommand(
|
||||||
std::string const& language, std::string const& sourceFileName,
|
std::string const& language, std::string const& sourceFileName,
|
||||||
|
@ -161,6 +175,7 @@ private:
|
||||||
cmLocalNinjaGenerator* LocalGenerator;
|
cmLocalNinjaGenerator* LocalGenerator;
|
||||||
/// List of object files for this target.
|
/// List of object files for this target.
|
||||||
cmNinjaDeps Objects;
|
cmNinjaDeps Objects;
|
||||||
|
cmNinjaDeps DDIFiles; // TODO: Make per-language.
|
||||||
std::vector<cmCustomCommand const*> CustomCommands;
|
std::vector<cmCustomCommand const*> CustomCommands;
|
||||||
cmNinjaDeps ExtraFiles;
|
cmNinjaDeps ExtraFiles;
|
||||||
};
|
};
|
||||||
|
|
|
@ -52,6 +52,11 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <time.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)
|
void CMakeCommandUsage(const char* program)
|
||||||
{
|
{
|
||||||
std::ostringstream errorStream;
|
std::ostringstream errorStream;
|
||||||
|
@ -782,6 +787,18 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
|
||||||
return cmcmd::ExecuteLinkScript(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.
|
// Internal CMake unimplemented feature notification.
|
||||||
else if (args[1] == "cmake_unimplemented_variable") {
|
else if (args[1] == "cmake_unimplemented_variable") {
|
||||||
std::cerr << "Feature not implemented for this platform.";
|
std::cerr << "Feature not implemented for this platform.";
|
||||||
|
|
Loading…
Reference in New Issue