Commit 93d5509b authored by Brad King's avatar Brad King
Browse files

Merge branch 'ninja-object-library' into object-library

* ninja-object-library: (37 commits)
  Ninja: Honor $<TARGET_OBJECTS:...> source expressions
  Build object library targets in Ninja
  Pre-compute object file names before Ninja generation
  Simplify cmNinjaTargetGenerator using cmGeneratorTarget
  Ninja: Avoid using 'this' in member initializers
  Ninja: Fix for PDB files with spaces in the path.
  Ninja: Constify use of cmCustomCommand
  Ninja: add /DEF: flag to linker call
  Ninja: Add a cache option CMAKE_ENABLE_NINJA to enable the ninja generator.
  Ninja: Add friend struct so it can access the private ConvertToNinjaPath.
  Ninja: add .def file support
  Ninja: ensure the output dir exists at compile time
  Ninja: Remove an unnecessary variable
  Ninja: Use cmSystemTools::ExpandListArgument to split compile/link commands
  Ninja: Add a missed license header
  Ninja: CMake: Adapt Ninja generator for per-target include dirs
  Ninja: windows msvc: create for each target a .pdb file
  Ninja: Import library support for Windows
  Ninja: mark the Windows specific hacks with a comment only
  Ninja: disable unfinished Windows ninja support
  ...
parents 821037cf 2693dbe0
#=============================================================================
# Copyright 2011 Kitware, Inc.
#
# 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.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
FIND_PROGRAM(CMAKE_MAKE_PROGRAM ninja
DOC "Program used to build from build.ninja files.")
MARK_AS_ADVANCED(CMAKE_MAKE_PROGRAM)
......@@ -24,6 +24,15 @@ macro(__compiler_gnu lang)
set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "-fPIC")
set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-shared")
# Older versions of gcc (< 4.5) contain a bug causing them to report a missing
# header file as a warning if depfiles are enabled, causing check_header_file
# tests to always succeed. Work around this by disabling dependency tracking
# in try_compile mode.
GET_PROPERTY(_IN_TC GLOBAL PROPERTY IN_TRY_COMPILE)
if(NOT _IN_TC OR CMAKE_FORCE_DEPFILES)
set(CMAKE_DEPFILE_FLAGS_${lang} "-MMD -MF <DEPFILE>")
endif()
# Initial configuration flags.
set(CMAKE_${lang}_FLAGS_INIT "")
set(CMAKE_${lang}_FLAGS_DEBUG_INIT "-g")
......
......@@ -833,6 +833,12 @@ function(ExternalProject_Add_StepTargets name)
foreach(step ${steps})
add_custom_target(${name}-${step}
DEPENDS ${stamp_dir}${cfgdir}/${name}-${step})
# Depend on other external projects (target-level).
get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
foreach(arg IN LISTS deps)
add_dependencies(${name}-${step} ${arg})
endforeach()
endforeach()
endfunction(ExternalProject_Add_StepTargets)
......@@ -1451,9 +1457,18 @@ function(ExternalProject_Add name)
# depends on the 'done' mark so that it rebuilds when this project
# rebuilds. It is important that 'done' is not the output of any
# custom command so that CMake does not propagate build rules to
# other external project targets.
# other external project targets, which may cause problems during
# parallel builds. However, the Ninja generator needs to see the entire
# dependency graph, and can cope with custom commands belonging to
# multiple targets, so we add the 'done' mark as an output for Ninja only.
set(complete_outputs ${cmf_dir}${cfgdir}/${name}-complete)
if(${CMAKE_GENERATOR} MATCHES "Ninja")
set(complete_outputs
${complete_outputs} ${stamp_dir}${cfgdir}/${name}-done)
endif()
add_custom_command(
OUTPUT ${cmf_dir}${cfgdir}/${name}-complete
OUTPUT ${complete_outputs}
COMMENT "Completed '${name}'"
COMMAND ${CMAKE_COMMAND} -E make_directory ${cmf_dir}${cfgdir}
COMMAND ${CMAKE_COMMAND} -E touch ${cmf_dir}${cfgdir}/${name}-complete
......
......@@ -37,7 +37,7 @@ SET(CMAKE_COMPILE_RESOURCE "rc <FLAGS> /fo<OBJECT> <SOURCE>")
# that is automatically copied into try_compile directories
# by the global generator.
SET(MSVC_IDE 1)
IF(CMAKE_GENERATOR MATCHES "Makefiles")
IF(CMAKE_GENERATOR MATCHES "Makefiles" OR CMAKE_GENERATOR MATCHES "Ninja")
SET(MSVC_IDE 0)
IF(NOT CMAKE_VC_COMPILER_TESTS_RUN)
SET(CMAKE_VC_COMPILER_TESTS 1)
......@@ -125,7 +125,7 @@ IF(CMAKE_GENERATOR MATCHES "Makefiles")
ENDIF(CMAKE_COMPILER_RETURN)
MAKE_DIRECTORY("${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp3")
ENDIF(NOT CMAKE_VC_COMPILER_TESTS_RUN)
ENDIF(CMAKE_GENERATOR MATCHES "Makefiles")
ENDIF(CMAKE_GENERATOR MATCHES "Makefiles" OR CMAKE_GENERATOR MATCHES "Ninja")
IF(MSVC_C_ARCHITECTURE_ID MATCHES 64)
SET(CMAKE_CL_64 1)
......
......@@ -355,6 +355,36 @@ IF (WIN32)
ENDIF(NOT UNIX)
ENDIF (WIN32)
# turn on Ninja by default
set(_CMAKE_DEFAULT_NINJA_VALUE TRUE)
# turn it off for platforms where it does not pass all the
# tests
if(WIN32 OR APPLE)
SET(_CMAKE_DEFAULT_NINJA_VALUE FALSE)
endif()
SET(CMAKE_ENABLE_NINJA ${_CMAKE_DEFAULT_NINJA_VALUE} CACHE BOOL
"Enable the ninja generator for CMake. currently not fully working for Windows or OSX")
MARK_AS_ADVANCED(CMAKE_ENABLE_NINJA)
IF(CMAKE_ENABLE_NINJA)
MESSAGE(STATUS "Enable ninja generator.")
SET(SRCS ${SRCS}
cmGlobalNinjaGenerator.cxx
cmGlobalNinjaGenerator.h
cmNinjaTypes.h
cmLocalNinjaGenerator.cxx
cmLocalNinjaGenerator.h
cmNinjaTargetGenerator.cxx
cmNinjaTargetGenerator.h
cmNinjaNormalTargetGenerator.cxx
cmNinjaNormalTargetGenerator.h
cmNinjaUtilityTargetGenerator.cxx
cmNinjaUtilityTargetGenerator.h
)
ADD_DEFINITIONS(-DCMAKE_USE_NINJA)
ELSE()
MESSAGE(STATUS "Disable ninja generator.")
ENDIF()
# create a library used by the command line and the GUI
ADD_LIBRARY(CMakeLib ${SRCS})
TARGET_LINK_LIBRARIES(CMakeLib cmsys
......
This diff is collapsed.
/*============================================================================
CMake - Cross Platform Makefile Generator
Copyright 2011 Peter Collingbourne <peter@pcc.me.uk>
Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com>
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.
============================================================================*/
#ifndef cmGlobalNinjaGenerator_h
# define cmGlobalNinjaGenerator_h
# include "cmGlobalGenerator.h"
# include "cmNinjaTypes.h"
class cmLocalGenerator;
class cmGeneratedFileStream;
class cmGeneratorTarget;
/**
* \class cmGlobalNinjaGenerator
* \brief Write a build.ninja file.
*
* The main differences between this generator and the UnixMakefile
* generator family are:
* - We don't care about VERBOSE variable or RULE_MESSAGES property since
* it is handle by Ninja's -v option.
* - We don't care about computing any progress status since Ninja manages
* it itself.
* - We don't care about generating a clean target since Ninja already have
* a clean tool.
* - We generate one build.ninja and one rules.ninja per project.
* - We try to minimize the number of generated rules: one per target and
* language.
* - We use Ninja special variable $in and $out to produce nice output.
* - We extensively use Ninja variable overloading system to minimize the
* number of generated rules.
*/
class cmGlobalNinjaGenerator : public cmGlobalGenerator
{
public:
/// The default name of Ninja's build file. Typically: build.ninja.
static const char* NINJA_BUILD_FILE;
/// The default name of Ninja's rules file. Typically: rules.ninja.
/// It is included in the main build.ninja file.
static const char* NINJA_RULES_FILE;
/// The indentation string used when generating Ninja's build file.
static const char* INDENT;
/// Write @a count times INDENT level to output stream @a os.
static void Indent(std::ostream& os, int count);
/// Write a divider in the given output stream @a os.
static void WriteDivider(std::ostream& os);
static std::string EncodeIdent(const std::string &ident, std::ostream &vars);
static std::string EncodeLiteral(const std::string &lit);
static std::string EncodePath(const std::string &path);
/**
* Write the given @a comment to the output stream @a os. It
* handles new line character properly.
*/
static void WriteComment(std::ostream& os, const std::string& comment);
/**
* Write a build statement to @a os with the @a comment using
* the @a rule the list of @a outputs files and inputs.
* It also writes the variables bound to this build statement.
* @warning no escaping of any kind is done here.
*/
static void WriteBuild(std::ostream& os,
const std::string& comment,
const std::string& rule,
const cmNinjaDeps& outputs,
const cmNinjaDeps& explicitDeps,
const cmNinjaDeps& implicitDeps,
const cmNinjaDeps& orderOnlyDeps,
const cmNinjaVars& variables);
/**
* Helper to write a build statement with the special 'phony' rule.
*/
static void WritePhonyBuild(std::ostream& os,
const std::string& comment,
const cmNinjaDeps& outputs,
const cmNinjaDeps& explicitDeps,
const cmNinjaDeps& implicitDeps = cmNinjaDeps(),
const cmNinjaDeps& orderOnlyDeps = cmNinjaDeps(),
const cmNinjaVars& variables = cmNinjaVars());
void WriteCustomCommandBuild(const std::string& command,
const std::string& description,
const std::string& comment,
const cmNinjaDeps& outputs,
const cmNinjaDeps& deps = cmNinjaDeps(),
const cmNinjaDeps& orderOnlyDeps = cmNinjaDeps());
/**
* Write a rule statement named @a name to @a os with the @a comment,
* the mandatory @a command, the @a depfile and the @a description.
* It also writes the variables bound to this rule statement.
* @warning no escaping of any kind is done here.
*/
static void WriteRule(std::ostream& os,
const std::string& name,
const std::string& command,
const std::string& description,
const std::string& comment = "",
const std::string& depfile = "",
bool restat = false,
bool generator = false);
/**
* Write a variable named @a name to @a os with value @a value and an
* optional @a comment. An @a indent level can be specified.
* @warning no escaping of any kind is done here.
*/
static void WriteVariable(std::ostream& os,
const std::string& name,
const std::string& value,
const std::string& comment = "",
int indent = 0);
/**
* Write an include statement including @a filename with an optional
* @a comment to the @a os stream.
*/
static void WriteInclude(std::ostream& os,
const std::string& filename,
const std::string& comment = "");
/**
* Write a default target statement specifying @a targets as
* the default targets.
*/
static void WriteDefault(std::ostream& os,
const cmNinjaDeps& targets,
const std::string& comment = "");
public:
/// Default constructor.
cmGlobalNinjaGenerator();
/// Convenience method for creating an instance of this class.
static cmGlobalGenerator* New() {
return new cmGlobalNinjaGenerator; }
/// Destructor.
virtual ~cmGlobalNinjaGenerator() { }
/// Overloaded methods. @see cmGlobalGenerator::CreateLocalGenerator()
virtual cmLocalGenerator* CreateLocalGenerator();
/// Overloaded methods. @see cmGlobalGenerator::GetName().
virtual const char* GetName() const {
return cmGlobalNinjaGenerator::GetActualName(); }
/// @return the name of this generator.
static const char* GetActualName() { return "Ninja"; }
/// Overloaded methods. @see cmGlobalGenerator::GetDocumentation()
virtual void GetDocumentation(cmDocumentationEntry& entry) const;
/// Overloaded methods. @see cmGlobalGenerator::Generate()
virtual void Generate();
/// Overloaded methods. @see cmGlobalGenerator::EnableLanguage()
virtual void EnableLanguage(std::vector<std::string>const& languages,
cmMakefile* mf,
bool optional);
/// Overloaded methods. @see cmGlobalGenerator::GenerateBuildCommand()
virtual std::string GenerateBuildCommand(const char* makeProgram,
const char* projectName,
const char* additionalOptions,
const char* targetName,
const char* config,
bool ignoreErrors,
bool fast);
// Setup target names
virtual const char* GetAllTargetName() const { return "all"; }
virtual const char* GetInstallTargetName() const { return "install"; }
virtual const char* GetInstallLocalTargetName() const {
return "install/local";
}
virtual const char* GetInstallStripTargetName() const {
return "install/strip";
}
virtual const char* GetTestTargetName() const { return "test"; }
virtual const char* GetPackageTargetName() const { return "package"; }
virtual const char* GetPackageSourceTargetName() const {
return "package_source";
}
virtual const char* GetEditCacheTargetName() const {
return "edit_cache";
}
virtual const char* GetRebuildCacheTargetName() const {
return "rebuild_cache";
}
virtual const char* GetCleanTargetName() const { return "clean"; }
public:
cmGeneratedFileStream* GetBuildFileStream() const
{ return this->BuildFileStream; }
cmGeneratedFileStream* GetRulesFileStream() const
{ return this->RulesFileStream; }
/**
* Add a rule to the generated build system.
* Call WriteRule() behind the scene but perform some check before like:
* - Do not add twice the same rule.
*/
void AddRule(const std::string& name,
const std::string& command,
const std::string& description,
const std::string& comment = "",
const std::string& depfile = "",
bool restat = false,
bool generator = false);
bool HasRule(const std::string& name);
void AddCustomCommandRule();
protected:
/// Overloaded methods.
/// @see cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS()
virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() { return true; }
private:
/// @see cmGlobalGenerator::ComputeTargetObjects
virtual void ComputeTargetObjects(cmGeneratorTarget* gt) const;
private:
// In order to access the AddDependencyToAll() functions and co.
friend class cmLocalNinjaGenerator;
// In order to access the SeenCustomCommand() function.
friend class cmNinjaTargetGenerator;
friend class cmNinjaNormalTargetGenerator;
friend class cmNinjaUtilityTargetGenerator;
private:
void OpenBuildFileStream();
void CloseBuildFileStream();
void OpenRulesFileStream();
void CloseRulesFileStream();
/// Write the common disclaimer text at the top of each build file.
void WriteDisclaimer(std::ostream& os);
void AddDependencyToAll(cmTarget* target);
void WriteAssumedSourceDependencies();
void AppendTargetOutputs(cmTarget* target, cmNinjaDeps& outputs);
void AppendTargetDepends(cmTarget* target, cmNinjaDeps& outputs);
void AddTargetAlias(const std::string& alias, cmTarget* target);
void WriteTargetAliases(std::ostream& os);
void WriteBuiltinTargets(std::ostream& os);
void WriteTargetAll(std::ostream& os);
void WriteTargetRebuildManifest(std::ostream& os);
/// Called when we have seen the given custom command. Returns true
/// if we has seen it before.
bool SeenCustomCommand(cmCustomCommand const *cc) {
return !this->CustomCommands.insert(cc).second;
}
/// Called when we have seen the given custom command output.
void SeenCustomCommandOutput(const std::string &output) {
this->CustomCommandOutputs.insert(output);
// We don't need the assumed dependencies anymore, because we have
// an output.
this->AssumedSourceDependencies.erase(output);
}
bool HasCustomCommandOutput(const std::string &output) {
return this->CustomCommandOutputs.find(output) !=
this->CustomCommandOutputs.end();
}
void AddAssumedSourceDependencies(const std::string &source,
const cmNinjaDeps &deps) {
std::set<std::string> &ASD = this->AssumedSourceDependencies[source];
// Because we may see the same source file multiple times (same source
// specified in multiple targets), compute the union of any assumed
// dependencies.
ASD.insert(deps.begin(), deps.end());
}
private:
/// The file containing the build statement. (the relation ship of the
/// compilation DAG).
cmGeneratedFileStream* BuildFileStream;
/// The file containing the rule statements. (The action attached to each
/// edge of the compilation DAG).
cmGeneratedFileStream* RulesFileStream;
/// The type used to store the set of rules added to the generated build
/// system.
typedef std::set<std::string> RulesSetType;
/// The set of rules added to the generated build system.
RulesSetType Rules;
/// The set of dependencies to add to the "all" target.
cmNinjaDeps AllDependencies;
/// The set of custom commands we have seen.
std::set<cmCustomCommand const*> CustomCommands;
/// The set of custom command outputs we have seen.
std::set<std::string> CustomCommandOutputs;
/// The mapping from source file to assumed dependencies.
std::map<std::string, std::set<std::string> > AssumedSourceDependencies;
typedef std::map<std::string, cmTarget*> TargetAliasMap;
TargetAliasMap TargetAliases;
static cmLocalGenerator* LocalGenerator;
};
#endif // ! cmGlobalNinjaGenerator_h
......@@ -1503,7 +1503,7 @@ void cmLocalGenerator::GetTargetFlags(std::string& linkLibs,
linkFlags +=
this->Makefile->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG");
linkFlags += this->Convert(sf->GetFullPath().c_str(),
START_OUTPUT, SHELL);
FULL, SHELL);
linkFlags += " ";
}
}
......@@ -1583,6 +1583,16 @@ void cmLocalGenerator::GetTargetFlags(std::string& linkLibs,
this->Makefile->GetSafeDefinition("CMAKE_CREATE_CONSOLE_EXE");
linkFlags += " ";
}
if (target.IsExecutableWithExports())
{
std::string exportFlagVar = "CMAKE_EXE_EXPORTS_";
exportFlagVar += linkLanguage;
exportFlagVar += "_FLAG";
linkFlags +=
this->Makefile->GetSafeDefinition(exportFlagVar.c_str());
linkFlags += " ";
}
const char* targetLinkFlags = target.GetProperty("LINK_FLAGS");
if(targetLinkFlags)
{
......
/*============================================================================
CMake - Cross Platform Makefile Generator
Copyright 2011 Peter Collingbourne <peter@pcc.me.uk>
Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com>
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.
============================================================================*/
#include "cmLocalNinjaGenerator.h"
#include "cmCustomCommandGenerator.h"
#include "cmMakefile.h"
#include "cmGlobalNinjaGenerator.h"
#include "cmNinjaTargetGenerator.h"
#include "cmGeneratedFileStream.h"
#include "cmSourceFile.h"
#include "cmComputeLinkInformation.h"
#include "cmake.h"
#include <assert.h>
cmLocalNinjaGenerator::cmLocalNinjaGenerator()
: cmLocalGenerator()
, ConfigName("")
, HomeRelativeOutputPath("")
{
this->IsMakefileGenerator = true;
#ifdef _WIN32
this->WindowsShell = true;
#endif
this->TargetImplib = "$TARGET_IMPLIB";
}
//----------------------------------------------------------------------------
// Virtual public methods.
cmLocalNinjaGenerator::~cmLocalNinjaGenerator()
{
}
void cmLocalNinjaGenerator::Generate()
{
this->SetConfigName();
this->WriteProcessedMakefile(this->GetBuildFileStream());
this->WriteProcessedMakefile(this->GetRulesFileStream());
this->WriteBuildFileTop();
cmTargets& targets = this->GetMakefile()->GetTargets();
for(cmTargets::iterator t = targets.begin(); t != targets.end(); ++t)
{
cmNinjaTargetGenerator* tg = cmNinjaTargetGenerator::New(&t->second);
if(tg)
{
tg->Generate();
// Add the target to "all" if required.
if (!this->GetGlobalNinjaGenerator()->IsExcluded(
this->GetGlobalNinjaGenerator()->LocalGenerators[0],
t->second))
this->GetGlobalNinjaGenerator()->AddDependencyToAll(&t->second);
delete tg;
}
}
this->WriteCustomCommandBuildStatements();
}
// Implemented in:
// cmLocalUnixMakefileGenerator3.
// Used in:
// Source/cmMakefile.cxx
// Source/cmGlobalGenerator.cxx
void cmLocalNinjaGenerator::Configure()
{
// Compute the path to use when referencing the current output
// directory from the top output directory.
this->HomeRelativeOutputPath =
this->Convert(this->Makefile->GetStartOutputDirectory(), HOME_OUTPUT);
if(this->HomeRelativeOutputPath == ".")
{
this->HomeRelativeOutputPath = "";
}
this->cmLocalGenerator::Configure();
}
// TODO: Picked up from cmLocalUnixMakefileGenerator3. Refactor it.
std::string cmLocalNinjaGenerator
::GetTargetDirectory(cmTarget const& target) const
{
std::string dir = cmake::GetCMakeFilesDirectoryPostSlash();
dir += target.GetName();
#if defined(__VMS)
dir += "_dir";
#else
dir += ".dir";
#endif
return dir;
}
//----------------------------------------------------------------------------
// Non-virtual public methods.
const cmGlobalNinjaGenerator*
cmLocalNinjaGenerator::GetGlobalNinjaGenerator() const
{
return
static_cast<const cmGlobalNinjaGenerator*>(this->GetGlobalGenerator());
}
cmGlobalNinjaGenerator* cmLocalNinjaGenerator::GetGlobalNinjaGenerator()
{
return static_cast<cmGlobalNinjaGenerator*>(this->GetGlobalGenerator());
}
//----------------------------------------------------------------------------
// Virtual protected methods.