summaryrefslogtreecommitdiffstats
path: root/Source/cmNinjaNormalTargetGenerator.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmNinjaNormalTargetGenerator.cxx')
-rw-r--r--Source/cmNinjaNormalTargetGenerator.cxx693
1 files changed, 693 insertions, 0 deletions
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
new file mode 100644
index 0000000..0cc3e3b
--- /dev/null
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -0,0 +1,693 @@
+/*============================================================================
+ 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 "cmNinjaNormalTargetGenerator.h"
+#include "cmLocalNinjaGenerator.h"
+#include "cmGlobalNinjaGenerator.h"
+#include "cmSourceFile.h"
+#include "cmGeneratedFileStream.h"
+#include "cmMakefile.h"
+#include "cmOSXBundleGenerator.h"
+#include "cmGeneratorTarget.h"
+#include "cmCustomCommandGenerator.h"
+
+#include <assert.h>
+#include <algorithm>
+
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+
+cmNinjaNormalTargetGenerator::
+cmNinjaNormalTargetGenerator(cmGeneratorTarget* target)
+ : cmNinjaTargetGenerator(target->Target)
+ , TargetNameOut()
+ , TargetNameSO()
+ , TargetNameReal()
+ , TargetNameImport()
+ , TargetNamePDB()
+ , TargetLinkLanguage("")
+{
+ this->TargetLinkLanguage = target->Target
+ ->GetLinkerLanguage(this->GetConfigName());
+ if (target->GetType() == cmTarget::EXECUTABLE)
+ target->Target->GetExecutableNames(this->TargetNameOut,
+ this->TargetNameReal,
+ this->TargetNameImport,
+ this->TargetNamePDB,
+ GetLocalGenerator()->GetConfigName());
+ else
+ target->Target->GetLibraryNames(this->TargetNameOut,
+ this->TargetNameSO,
+ this->TargetNameReal,
+ this->TargetNameImport,
+ this->TargetNamePDB,
+ GetLocalGenerator()->GetConfigName());
+
+ if(target->GetType() != cmTarget::OBJECT_LIBRARY)
+ {
+ // on Windows the output dir is already needed at compile time
+ // ensure the directory exists (OutDir test)
+ EnsureDirectoryExists(target->Target->GetDirectory(this->GetConfigName()));
+ }
+
+ this->OSXBundleGenerator = new cmOSXBundleGenerator(target,
+ this->GetConfigName());
+ this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
+}
+
+cmNinjaNormalTargetGenerator::~cmNinjaNormalTargetGenerator()
+{
+ delete this->OSXBundleGenerator;
+}
+
+void cmNinjaNormalTargetGenerator::Generate()
+{
+ if (this->TargetLinkLanguage.empty()) {
+ cmSystemTools::Error("CMake can not determine linker language for "
+ "target: ",
+ this->GetTarget()->GetName().c_str());
+ return;
+ }
+
+ // Write the rules for each language.
+ this->WriteLanguagesRules();
+
+ // Write the build statements
+ this->WriteObjectBuildStatements();
+
+ if(this->GetTarget()->GetType() == cmTarget::OBJECT_LIBRARY)
+ {
+ this->WriteObjectLibStatement();
+ }
+ else
+ {
+ this->WriteLinkRule(false); // write rule without rspfile support
+ this->WriteLinkRule(true); // write rule with rspfile support
+ this->WriteLinkStatement();
+ }
+}
+
+void cmNinjaNormalTargetGenerator::WriteLanguagesRules()
+{
+#ifdef NINJA_GEN_VERBOSE_FILES
+ cmGlobalNinjaGenerator::WriteDivider(this->GetRulesFileStream());
+ this->GetRulesFileStream()
+ << "# Rules for each languages for "
+ << cmTarget::GetTargetTypeName(this->GetTarget()->GetType())
+ << " target "
+ << this->GetTargetName()
+ << "\n\n";
+#endif
+
+ std::set<std::string> languages;
+ this->GetTarget()->GetLanguages(languages,
+ this->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE"));
+ for(std::set<std::string>::const_iterator l = languages.begin();
+ l != languages.end();
+ ++l)
+ this->WriteLanguageRules(*l);
+}
+
+const char *cmNinjaNormalTargetGenerator::GetVisibleTypeName() const
+{
+ switch (this->GetTarget()->GetType()) {
+ case cmTarget::STATIC_LIBRARY:
+ return "static library";
+ case cmTarget::SHARED_LIBRARY:
+ return "shared library";
+ case cmTarget::MODULE_LIBRARY:
+ if (this->GetTarget()->IsCFBundleOnApple())
+ return "CFBundle shared module";
+ else
+ return "shared module";
+ case cmTarget::EXECUTABLE:
+ return "executable";
+ default:
+ return 0;
+ }
+}
+
+std::string
+cmNinjaNormalTargetGenerator
+::LanguageLinkerRule() const
+{
+ return this->TargetLinkLanguage
+ + "_"
+ + cmTarget::GetTargetTypeName(this->GetTarget()->GetType())
+ + "_LINKER";
+}
+
+void
+cmNinjaNormalTargetGenerator
+::WriteLinkRule(bool useResponseFile)
+{
+ cmTarget::TargetType targetType = this->GetTarget()->GetType();
+ std::string ruleName = this->LanguageLinkerRule();
+ if (useResponseFile)
+ ruleName += "_RSP_FILE";
+
+ // Select whether to use a response file for objects.
+ std::string rspfile;
+ std::string rspcontent;
+
+ if (!this->GetGlobalGenerator()->HasRule(ruleName)) {
+ cmLocalGenerator::RuleVariables vars;
+ vars.RuleLauncher = "RULE_LAUNCH_LINK";
+ vars.CMTarget = this->GetTarget();
+ vars.Language = this->TargetLinkLanguage.c_str();
+
+ std::string responseFlag;
+ if (!useResponseFile) {
+ vars.Objects = "$in";
+ vars.LinkLibraries = "$LINK_PATH $LINK_LIBRARIES";
+ } else {
+ std::string cmakeVarLang = "CMAKE_";
+ cmakeVarLang += this->TargetLinkLanguage;
+
+ // build response file name
+ std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG";
+ const char * flag = GetMakefile()->GetDefinition(cmakeLinkVar);
+ if(flag) {
+ responseFlag = flag;
+ } else {
+ responseFlag = "@";
+ }
+ rspfile = "$RSP_FILE";
+ responseFlag += rspfile;
+
+ // build response file content
+ rspcontent = "$in_newline $LINK_PATH $LINK_LIBRARIES";
+ vars.Objects = responseFlag.c_str();
+ vars.LinkLibraries = "";
+ }
+
+ vars.ObjectDir = "$OBJECT_DIR";
+
+ // TODO:
+ // Makefile generator expands <TARGET> to the plain target name
+ // with suffix. $out expands to a relative path. This difference
+ // could make trouble when switching to Ninja generator. Maybe
+ // using TARGET_NAME and RuleVariables::TargetName is a fix.
+ vars.Target = "$out";
+
+ vars.SONameFlag = "$SONAME_FLAG";
+ vars.TargetSOName = "$SONAME";
+ vars.TargetInstallNameDir = "$INSTALLNAME_DIR";
+ vars.TargetPDB = "$TARGET_PDB";
+
+ // Setup the target version.
+ std::string targetVersionMajor;
+ std::string targetVersionMinor;
+ {
+ cmOStringStream majorStream;
+ cmOStringStream minorStream;
+ int major;
+ int minor;
+ this->GetTarget()->GetTargetVersion(major, minor);
+ majorStream << major;
+ minorStream << minor;
+ targetVersionMajor = majorStream.str();
+ targetVersionMinor = minorStream.str();
+ }
+ vars.TargetVersionMajor = targetVersionMajor.c_str();
+ vars.TargetVersionMinor = targetVersionMinor.c_str();
+
+ vars.Flags = "$FLAGS";
+ vars.LinkFlags = "$LINK_FLAGS";
+
+ std::string langFlags;
+ if (targetType != cmTarget::EXECUTABLE)
+ {
+ langFlags += "$LANGUAGE_COMPILE_FLAGS $ARCH_FLAGS";
+ vars.LanguageCompileFlags = langFlags.c_str();
+ }
+
+ // Rule for linking library/executable.
+ std::vector<std::string> linkCmds = this->ComputeLinkCmd();
+ for(std::vector<std::string>::iterator i = linkCmds.begin();
+ i != linkCmds.end();
+ ++i)
+ {
+ this->GetLocalGenerator()->ExpandRuleVariables(*i, vars);
+ }
+ linkCmds.insert(linkCmds.begin(), "$PRE_LINK");
+ linkCmds.push_back("$POST_BUILD");
+ std::string linkCmd =
+ this->GetLocalGenerator()->BuildCommandLine(linkCmds);
+
+ // Write the linker rule with response file if needed.
+ cmOStringStream comment;
+ comment << "Rule for linking " << this->TargetLinkLanguage << " "
+ << this->GetVisibleTypeName() << ".";
+ cmOStringStream description;
+ description << "Linking " << this->TargetLinkLanguage << " "
+ << this->GetVisibleTypeName() << " $out";
+ this->GetGlobalGenerator()->AddRule(ruleName,
+ linkCmd,
+ description.str(),
+ comment.str(),
+ /*depfile*/ "",
+ /*deptype*/ "",
+ rspfile,
+ rspcontent,
+ /*restat*/ false,
+ /*generator*/ false);
+ }
+
+ if (this->TargetNameOut != this->TargetNameReal &&
+ !this->GetTarget()->IsFrameworkOnApple()) {
+ std::string cmakeCommand =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ this->GetMakefile()->GetRequiredDefinition("CMAKE_COMMAND"),
+ cmLocalGenerator::SHELL);
+ if (targetType == cmTarget::EXECUTABLE)
+ this->GetGlobalGenerator()->AddRule("CMAKE_SYMLINK_EXECUTABLE",
+ cmakeCommand +
+ " -E cmake_symlink_executable"
+ " $in $out && $POST_BUILD",
+ "Creating executable symlink $out",
+ "Rule for creating "
+ "executable symlink.",
+ /*depfile*/ "",
+ /*deptype*/ "",
+ /*rspfile*/ "",
+ /*rspcontent*/ "",
+ /*restat*/ false,
+ /*generator*/ false);
+ else
+ this->GetGlobalGenerator()->AddRule("CMAKE_SYMLINK_LIBRARY",
+ cmakeCommand +
+ " -E cmake_symlink_library"
+ " $in $SONAME $out && $POST_BUILD",
+ "Creating library symlink $out",
+ "Rule for creating "
+ "library symlink.",
+ /*depfile*/ "",
+ /*deptype*/ "",
+ /*rspfile*/ "",
+ /*rspcontent*/ "",
+ /*restat*/ false,
+ /*generator*/ false);
+ }
+}
+
+std::vector<std::string>
+cmNinjaNormalTargetGenerator
+::ComputeLinkCmd()
+{
+ std::vector<std::string> linkCmds;
+ cmMakefile* mf = this->GetMakefile();
+ {
+ std::string linkCmdVar = this->GetGeneratorTarget()
+ ->GetCreateRuleVariable(this->TargetLinkLanguage, this->GetConfigName());
+ const char *linkCmd = mf->GetDefinition(linkCmdVar);
+ if (linkCmd)
+ {
+ cmSystemTools::ExpandListArgument(linkCmd, linkCmds);
+ return linkCmds;
+ }
+ }
+ switch (this->GetTarget()->GetType()) {
+ case cmTarget::STATIC_LIBRARY: {
+ // We have archive link commands set. First, delete the existing archive.
+ {
+ std::string cmakeCommand =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ mf->GetRequiredDefinition("CMAKE_COMMAND"),
+ cmLocalGenerator::SHELL);
+ linkCmds.push_back(cmakeCommand + " -E remove $out");
+ }
+ // TODO: Use ARCHIVE_APPEND for archives over a certain size.
+ {
+ std::string linkCmdVar = "CMAKE_";
+ linkCmdVar += this->TargetLinkLanguage;
+ linkCmdVar += "_ARCHIVE_CREATE";
+ const char *linkCmd = mf->GetRequiredDefinition(linkCmdVar);
+ cmSystemTools::ExpandListArgument(linkCmd, linkCmds);
+ }
+ {
+ std::string linkCmdVar = "CMAKE_";
+ linkCmdVar += this->TargetLinkLanguage;
+ linkCmdVar += "_ARCHIVE_FINISH";
+ const char *linkCmd = mf->GetRequiredDefinition(linkCmdVar);
+ cmSystemTools::ExpandListArgument(linkCmd, linkCmds);
+ }
+ return linkCmds;
+ }
+ case cmTarget::SHARED_LIBRARY:
+ case cmTarget::MODULE_LIBRARY:
+ case cmTarget::EXECUTABLE:
+ break;
+ default:
+ assert(0 && "Unexpected target type");
+ }
+ return std::vector<std::string>();
+}
+
+
+static int calculateCommandLineLengthLimit(int linkRuleLength)
+{
+#ifdef _WIN32
+ return 8000 - linkRuleLength;
+#elif defined(__linux) || defined(__APPLE__) || defined(__HAIKU__)
+ // for instance ARG_MAX is 2096152 on Ubuntu or 262144 on Mac
+ return ((int)sysconf(_SC_ARG_MAX)) - linkRuleLength - 1000;
+#else
+ (void)linkRuleLength;
+ return -1;
+#endif
+}
+
+
+void cmNinjaNormalTargetGenerator::WriteLinkStatement()
+{
+ cmTarget& target = *this->GetTarget();
+ const std::string cfgName = this->GetConfigName();
+ std::string targetOutput = ConvertToNinjaPath(
+ target.GetFullPath(cfgName));
+ std::string targetOutputReal = ConvertToNinjaPath(
+ target.GetFullPath(cfgName,
+ /*implib=*/false,
+ /*realpath=*/true));
+ std::string targetOutputImplib = ConvertToNinjaPath(
+ target.GetFullPath(cfgName,
+ /*implib=*/true));
+
+ if (target.IsAppBundleOnApple())
+ {
+ // Create the app bundle
+ std::string outpath = target.GetDirectory(cfgName);
+ this->OSXBundleGenerator->CreateAppBundle(this->TargetNameOut, outpath);
+
+ // Calculate the output path
+ targetOutput = outpath;
+ targetOutput += "/";
+ targetOutput += this->TargetNameOut;
+ targetOutput = this->ConvertToNinjaPath(targetOutput);
+ targetOutputReal = outpath;
+ targetOutputReal += "/";
+ targetOutputReal += this->TargetNameReal;
+ targetOutputReal = this->ConvertToNinjaPath(targetOutputReal);
+ }
+ else if (target.IsFrameworkOnApple())
+ {
+ // Create the library framework.
+ this->OSXBundleGenerator->CreateFramework(this->TargetNameOut,
+ target.GetDirectory(cfgName));
+ }
+ else if(target.IsCFBundleOnApple())
+ {
+ // Create the core foundation bundle.
+ this->OSXBundleGenerator->CreateCFBundle(this->TargetNameOut,
+ target.GetDirectory(cfgName));
+ }
+
+ // Write comments.
+ cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream());
+ const cmTarget::TargetType targetType = target.GetType();
+ this->GetBuildFileStream()
+ << "# Link build statements for "
+ << cmTarget::GetTargetTypeName(targetType)
+ << " target "
+ << this->GetTargetName()
+ << "\n\n";
+
+ cmNinjaDeps emptyDeps;
+ cmNinjaVars vars;
+
+ // Compute the comment.
+ cmOStringStream comment;
+ comment <<
+ "Link the " << this->GetVisibleTypeName() << " " << targetOutputReal;
+
+ // Compute outputs.
+ cmNinjaDeps outputs;
+ outputs.push_back(targetOutputReal);
+
+ // Compute specific libraries to link with.
+ cmNinjaDeps explicitDeps = this->GetObjects();
+ cmNinjaDeps implicitDeps = this->ComputeLinkDeps();
+
+ cmMakefile* mf = this->GetMakefile();
+
+ std::string frameworkPath;
+ std::string linkPath;
+ cmGeneratorTarget& genTarget = *this->GetGeneratorTarget();
+
+ std::string createRule =
+ genTarget.GetCreateRuleVariable(this->TargetLinkLanguage,
+ this->GetConfigName());
+ bool useWatcomQuote = mf->IsOn(createRule+"_USE_WATCOM_QUOTE");
+ cmLocalNinjaGenerator& localGen = *this->GetLocalGenerator();
+ localGen.GetTargetFlags(vars["LINK_LIBRARIES"],
+ vars["FLAGS"],
+ vars["LINK_FLAGS"],
+ frameworkPath,
+ linkPath,
+ &genTarget,
+ useWatcomQuote);
+
+ this->addPoolNinjaVariable("JOB_POOL_LINK", &target, vars);
+
+ this->AddModuleDefinitionFlag(vars["LINK_FLAGS"]);
+ vars["LINK_FLAGS"] = cmGlobalNinjaGenerator
+ ::EncodeLiteral(vars["LINK_FLAGS"]);
+
+ vars["LINK_PATH"] = frameworkPath + linkPath;
+
+ // Compute architecture specific link flags. Yes, these go into a different
+ // variable for executables, probably due to a mistake made when duplicating
+ // code between the Makefile executable and library generators.
+ if (targetType == cmTarget::EXECUTABLE)
+ {
+ std::string t = vars["FLAGS"];
+ localGen.AddArchitectureFlags(t, &genTarget, TargetLinkLanguage, cfgName);
+ vars["FLAGS"] = t;
+ }
+ else
+ {
+ std::string t = vars["ARCH_FLAGS"];
+ localGen.AddArchitectureFlags(t, &genTarget, TargetLinkLanguage, cfgName);
+ vars["ARCH_FLAGS"] = t;
+ t = "";
+ localGen.AddLanguageFlags(t, TargetLinkLanguage, cfgName);
+ vars["LANGUAGE_COMPILE_FLAGS"] = t;
+ }
+
+ if (target.HasSOName(cfgName))
+ {
+ vars["SONAME_FLAG"] = mf->GetSONameFlag(this->TargetLinkLanguage);
+ vars["SONAME"] = this->TargetNameSO;
+ if (targetType == cmTarget::SHARED_LIBRARY)
+ {
+ std::string install_dir = target.GetInstallNameDirForBuildTree(cfgName);
+ if (!install_dir.empty())
+ {
+ vars["INSTALLNAME_DIR"] = localGen.Convert(install_dir,
+ cmLocalGenerator::NONE,
+ cmLocalGenerator::SHELL,
+ false);
+ }
+ }
+ }
+
+ if (!this->TargetNameImport.empty())
+ {
+ const std::string impLibPath = localGen.ConvertToOutputFormat(
+ targetOutputImplib,
+ cmLocalGenerator::SHELL);
+ vars["TARGET_IMPLIB"] = impLibPath;
+ EnsureParentDirectoryExists(impLibPath);
+ }
+
+ if (!this->SetMsvcTargetPdbVariable(vars))
+ {
+ // It is common to place debug symbols at a specific place,
+ // so we need a plain target name in the rule available.
+ std::string prefix;
+ std::string base;
+ std::string suffix;
+ target.GetFullNameComponents(prefix, base, suffix);
+ std::string dbg_suffix = ".dbg";
+ // TODO: Where to document?
+ if (mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX"))
+ {
+ dbg_suffix = mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX");
+ }
+ vars["TARGET_PDB"] = base + suffix + dbg_suffix;
+ }
+
+ if (mf->IsOn("CMAKE_COMPILER_IS_MINGW"))
+ {
+ const std::string objPath = GetTarget()->GetSupportDirectory();
+ vars["OBJECT_DIR"] = ConvertToNinjaPath(objPath);
+ EnsureDirectoryExists(objPath);
+ // ar.exe can't handle backslashes in rsp files (implicitly used by gcc)
+ std::string& linkLibraries = vars["LINK_LIBRARIES"];
+ std::replace(linkLibraries.begin(), linkLibraries.end(), '\\', '/');
+ std::string& link_path = vars["LINK_PATH"];
+ std::replace(link_path.begin(), link_path.end(), '\\', '/');
+ }
+
+ const std::vector<cmCustomCommand> *cmdLists[3] = {
+ &target.GetPreBuildCommands(),
+ &target.GetPreLinkCommands(),
+ &target.GetPostBuildCommands()
+ };
+
+ std::vector<std::string> preLinkCmdLines, postBuildCmdLines;
+ std::vector<std::string> *cmdLineLists[3] = {
+ &preLinkCmdLines,
+ &preLinkCmdLines,
+ &postBuildCmdLines
+ };
+
+ for (unsigned i = 0; i != 3; ++i)
+ {
+ for (std::vector<cmCustomCommand>::const_iterator
+ ci = cmdLists[i]->begin();
+ ci != cmdLists[i]->end(); ++ci)
+ {
+ cmCustomCommandGenerator ccg(*ci, cfgName, mf);
+ localGen.AppendCustomCommandLines(ccg, *cmdLineLists[i]);
+ }
+ }
+
+ // If we have any PRE_LINK commands, we need to go back to HOME_OUTPUT for
+ // the link commands.
+ if (!preLinkCmdLines.empty())
+ {
+ const std::string homeOutDir = localGen.ConvertToOutputFormat(
+ mf->GetHomeOutputDirectory(),
+ cmLocalGenerator::SHELL);
+ preLinkCmdLines.push_back("cd " + homeOutDir);
+ }
+
+ vars["PRE_LINK"] = localGen.BuildCommandLine(preLinkCmdLines);
+ std::string postBuildCmdLine = localGen.BuildCommandLine(postBuildCmdLines);
+
+ cmNinjaVars symlinkVars;
+ if (targetOutput == targetOutputReal)
+ {
+ vars["POST_BUILD"] = postBuildCmdLine;
+ }
+ else
+ {
+ vars["POST_BUILD"] = ":";
+ symlinkVars["POST_BUILD"] = postBuildCmdLine;
+ }
+
+ cmGlobalNinjaGenerator& globalGen = *this->GetGlobalGenerator();
+
+ int commandLineLengthLimit = 1;
+ const char* forceRspFile = "CMAKE_NINJA_FORCE_RESPONSE_FILE";
+ if (!mf->IsDefinitionSet(forceRspFile) &&
+ cmSystemTools::GetEnv(forceRspFile) == 0)
+ {
+ commandLineLengthLimit = calculateCommandLineLengthLimit(
+ globalGen.GetRuleCmdLength(this->LanguageLinkerRule()));
+ }
+
+ const std::string rspfile =
+ std::string(cmake::GetCMakeFilesDirectoryPostSlash())
+ + target.GetName() + ".rsp";
+
+ // Gather order-only dependencies.
+ cmNinjaDeps orderOnlyDeps;
+ this->GetLocalGenerator()->AppendTargetDepends(this->GetTarget(),
+ orderOnlyDeps);
+
+ // Write the build statement for this target.
+ globalGen.WriteBuild(this->GetBuildFileStream(),
+ comment.str(),
+ this->LanguageLinkerRule(),
+ outputs,
+ explicitDeps,
+ implicitDeps,
+ orderOnlyDeps,
+ vars,
+ rspfile,
+ commandLineLengthLimit);
+
+ if (targetOutput != targetOutputReal && !target.IsFrameworkOnApple())
+ {
+ if (targetType == cmTarget::EXECUTABLE)
+ {
+ globalGen.WriteBuild(this->GetBuildFileStream(),
+ "Create executable symlink " + targetOutput,
+ "CMAKE_SYMLINK_EXECUTABLE",
+ cmNinjaDeps(1, targetOutput),
+ cmNinjaDeps(1, targetOutputReal),
+ emptyDeps,
+ emptyDeps,
+ symlinkVars);
+ }
+ else
+ {
+ cmNinjaDeps symlinks;
+ const std::string soName = this->GetTargetFilePath(this->TargetNameSO);
+ // If one link has to be created.
+ if (targetOutputReal == soName || targetOutput == soName)
+ {
+ symlinkVars["SONAME"] = soName;
+ }
+ else
+ {
+ symlinkVars["SONAME"] = "";
+ symlinks.push_back(soName);
+ }
+ symlinks.push_back(targetOutput);
+ globalGen.WriteBuild(this->GetBuildFileStream(),
+ "Create library symlink " + targetOutput,
+ "CMAKE_SYMLINK_LIBRARY",
+ symlinks,
+ cmNinjaDeps(1, targetOutputReal),
+ emptyDeps,
+ emptyDeps,
+ symlinkVars);
+ }
+ }
+
+ if (!this->TargetNameImport.empty())
+ {
+ // Since using multiple outputs would mess up the $out variable, use an
+ // alias for the import library.
+ globalGen.WritePhonyBuild(this->GetBuildFileStream(),
+ "Alias for import library.",
+ cmNinjaDeps(1, targetOutputImplib),
+ cmNinjaDeps(1, targetOutputReal));
+ }
+
+ // Add aliases for the file name and the target name.
+ globalGen.AddTargetAlias(this->TargetNameOut, &target);
+ globalGen.AddTargetAlias(this->GetTargetName(), &target);
+}
+
+//----------------------------------------------------------------------------
+void cmNinjaNormalTargetGenerator::WriteObjectLibStatement()
+{
+ // Write a phony output that depends on all object files.
+ cmNinjaDeps outputs;
+ this->GetLocalGenerator()->AppendTargetOutputs(this->GetTarget(), outputs);
+ cmNinjaDeps depends = this->GetObjects();
+ this->GetGlobalGenerator()->WritePhonyBuild(this->GetBuildFileStream(),
+ "Object library "
+ + this->GetTargetName(),
+ outputs,
+ depends);
+
+ // Add aliases for the target name.
+ this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
+ this->GetTarget());
+}