Merge topic 'ninja-link-with-compile-flags'

97f2b7f5 Ninja: set correct LANGUAGE_COMPILE_FLAGS when linking
49fcffc6 Ninja: cmake formatting, make code more readable
b735c8cb MinGW: link like on Unix and use compile flags when linking
This commit is contained in:
Brad King 2014-04-15 10:22:32 -04:00 committed by CMake Topic Stage
commit 60d1882a67
2 changed files with 164 additions and 150 deletions

View File

@ -113,9 +113,9 @@ macro(__windows_compiler_gnu lang)
# Binary link rules. # Binary link rules.
set(CMAKE_${lang}_CREATE_SHARED_MODULE set(CMAKE_${lang}_CREATE_SHARED_MODULE
"<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_MODULE_${lang}_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_MODULE_CREATE_${lang}_FLAGS> -o <TARGET> ${CMAKE_GNULD_IMAGE_VERSION} <OBJECTS> <LINK_LIBRARIES>") "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_MODULE_${lang}_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_MODULE_CREATE_${lang}_FLAGS> -o <TARGET> ${CMAKE_GNULD_IMAGE_VERSION} <OBJECTS> <LINK_LIBRARIES>")
set(CMAKE_${lang}_CREATE_SHARED_LIBRARY set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
"<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB> ${CMAKE_GNULD_IMAGE_VERSION} <OBJECTS> <LINK_LIBRARIES>") "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB> ${CMAKE_GNULD_IMAGE_VERSION} <OBJECTS> <LINK_LIBRARIES>")
set(CMAKE_${lang}_LINK_EXECUTABLE set(CMAKE_${lang}_LINK_EXECUTABLE
"<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB> ${CMAKE_GNULD_IMAGE_VERSION} <LINK_LIBRARIES>") "<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB> ${CMAKE_GNULD_IMAGE_VERSION} <LINK_LIBRARIES>")

View File

@ -232,13 +232,11 @@ cmNinjaNormalTargetGenerator
vars.LinkFlags = "$LINK_FLAGS"; vars.LinkFlags = "$LINK_FLAGS";
std::string langFlags; std::string langFlags;
if (targetType != cmTarget::EXECUTABLE) { if (targetType != cmTarget::EXECUTABLE)
this->GetLocalGenerator()->AddLanguageFlags(langFlags, {
this->TargetLinkLanguage, langFlags += "$LANGUAGE_COMPILE_FLAGS $ARCH_FLAGS";
this->GetConfigName());
langFlags += " $ARCH_FLAGS";
vars.LanguageCompileFlags = langFlags.c_str(); vars.LanguageCompileFlags = langFlags.c_str();
} }
// Rule for linking library/executable. // Rule for linking library/executable.
std::vector<std::string> linkCmds = this->ComputeLinkCmd(); std::vector<std::string> linkCmds = this->ComputeLinkCmd();
@ -363,25 +361,39 @@ cmNinjaNormalTargetGenerator
return std::vector<std::string>(); 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() void cmNinjaNormalTargetGenerator::WriteLinkStatement()
{ {
cmTarget::TargetType targetType = this->GetTarget()->GetType(); cmTarget& target = *this->GetTarget();
const std::string cfgName = this->GetConfigName();
std::string targetOutput = ConvertToNinjaPath( std::string targetOutput = ConvertToNinjaPath(
this->GetTarget()->GetFullPath(this->GetConfigName()).c_str()); target.GetFullPath(cfgName).c_str());
std::string targetOutputReal = ConvertToNinjaPath( std::string targetOutputReal = ConvertToNinjaPath(
this->GetTarget()->GetFullPath(this->GetConfigName(), target.GetFullPath(cfgName,
/*implib=*/false, /*implib=*/false,
/*realpath=*/true).c_str()); /*realpath=*/true).c_str());
std::string targetOutputImplib = ConvertToNinjaPath( std::string targetOutputImplib = ConvertToNinjaPath(
this->GetTarget()->GetFullPath(this->GetConfigName(), target.GetFullPath(cfgName,
/*implib=*/true).c_str()); /*implib=*/true).c_str());
if (this->GetTarget()->IsAppBundleOnApple()) if (target.IsAppBundleOnApple())
{ {
// Create the app bundle // Create the app bundle
std::string outpath = std::string outpath = target.GetDirectory(cfgName);
this->GetTarget()->GetDirectory(this->GetConfigName());
this->OSXBundleGenerator->CreateAppBundle(this->TargetNameOut, outpath); this->OSXBundleGenerator->CreateAppBundle(this->TargetNameOut, outpath);
// Calculate the output path // Calculate the output path
@ -394,23 +406,22 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
targetOutputReal += this->TargetNameReal; targetOutputReal += this->TargetNameReal;
targetOutputReal = this->ConvertToNinjaPath(targetOutputReal.c_str()); targetOutputReal = this->ConvertToNinjaPath(targetOutputReal.c_str());
} }
else if (this->GetTarget()->IsFrameworkOnApple()) else if (target.IsFrameworkOnApple())
{ {
// Create the library framework. // Create the library framework.
std::string outpath = this->OSXBundleGenerator->CreateFramework(this->TargetNameOut,
this->GetTarget()->GetDirectory(this->GetConfigName()); target.GetDirectory(cfgName));
this->OSXBundleGenerator->CreateFramework(this->TargetNameOut, outpath);
} }
else if(this->GetTarget()->IsCFBundleOnApple()) else if(target.IsCFBundleOnApple())
{ {
// Create the core foundation bundle. // Create the core foundation bundle.
std::string outpath = this->OSXBundleGenerator->CreateCFBundle(this->TargetNameOut,
this->GetTarget()->GetDirectory(this->GetConfigName()); target.GetDirectory(cfgName));
this->OSXBundleGenerator->CreateCFBundle(this->TargetNameOut, outpath);
} }
// Write comments. // Write comments.
cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream()); cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream());
const cmTarget::TargetType targetType = target.GetType();
this->GetBuildFileStream() this->GetBuildFileStream()
<< "# Link build statements for " << "# Link build statements for "
<< cmTarget::GetTargetTypeName(targetType) << cmTarget::GetTargetTypeName(targetType)
@ -423,8 +434,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
// Compute the comment. // Compute the comment.
cmOStringStream comment; cmOStringStream comment;
comment << "Link the " << this->GetVisibleTypeName() << " " comment <<
<< targetOutputReal; "Link the " << this->GetVisibleTypeName() << " " << targetOutputReal;
// Compute outputs. // Compute outputs.
cmNinjaDeps outputs; cmNinjaDeps outputs;
@ -438,21 +449,21 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
std::string frameworkPath; std::string frameworkPath;
std::string linkPath; std::string linkPath;
cmGeneratorTarget* gtarget = this->GetGeneratorTarget(); cmGeneratorTarget& genTarget = *this->GetGeneratorTarget();
std::string createRule = "CMAKE_"; std::string createRule = "CMAKE_";
createRule += this->TargetLinkLanguage; createRule += this->TargetLinkLanguage + genTarget.GetCreateRuleVariable();
createRule += gtarget->GetCreateRuleVariable();
bool useWatcomQuote = mf->IsOn(createRule+"_USE_WATCOM_QUOTE"); bool useWatcomQuote = mf->IsOn(createRule+"_USE_WATCOM_QUOTE");
this->GetLocalGenerator()->GetTargetFlags(vars["LINK_LIBRARIES"], cmLocalNinjaGenerator& localGen = *this->GetLocalGenerator();
vars["FLAGS"], localGen.GetTargetFlags(vars["LINK_LIBRARIES"],
vars["LINK_FLAGS"], vars["FLAGS"],
frameworkPath, vars["LINK_FLAGS"],
linkPath, frameworkPath,
gtarget, linkPath,
useWatcomQuote); &genTarget,
useWatcomQuote);
this->addPoolNinjaVariable("JOB_POOL_LINK", this->GetTarget(), vars); this->addPoolNinjaVariable("JOB_POOL_LINK", &target, vars);
this->AddModuleDefinitionFlag(vars["LINK_FLAGS"]); this->AddModuleDefinitionFlag(vars["LINK_FLAGS"]);
vars["LINK_FLAGS"] = cmGlobalNinjaGenerator vars["LINK_FLAGS"] = cmGlobalNinjaGenerator
@ -463,42 +474,47 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
// Compute architecture specific link flags. Yes, these go into a different // Compute architecture specific link flags. Yes, these go into a different
// variable for executables, probably due to a mistake made when duplicating // variable for executables, probably due to a mistake made when duplicating
// code between the Makefile executable and library generators. // code between the Makefile executable and library generators.
std::string flags = (targetType == cmTarget::EXECUTABLE if (targetType == cmTarget::EXECUTABLE)
? vars["FLAGS"] {
: vars["ARCH_FLAGS"]); std::string t = vars["FLAGS"];
this->GetLocalGenerator()->AddArchitectureFlags(flags, localGen.AddArchitectureFlags(t, &genTarget, TargetLinkLanguage, cfgName);
gtarget, vars["FLAGS"] = t;
this->TargetLinkLanguage, }
this->GetConfigName()); else
if (targetType == cmTarget::EXECUTABLE) { {
vars["FLAGS"] = flags; std::string t = vars["ARCH_FLAGS"];
} else { localGen.AddArchitectureFlags(t, &genTarget, TargetLinkLanguage, cfgName);
vars["ARCH_FLAGS"] = flags; vars["ARCH_FLAGS"] = t;
} t = "";
if (this->GetTarget()->HasSOName(this->GetConfigName())) { localGen.AddLanguageFlags(t, TargetLinkLanguage, cfgName);
vars["SONAME_FLAG"] = vars["LANGUAGE_COMPILE_FLAGS"] = t;
mf->GetSONameFlag(this->TargetLinkLanguage); }
vars["SONAME"] = this->TargetNameSO;
if (targetType == cmTarget::SHARED_LIBRARY) {
std::string install_name_dir = this->GetTarget()
->GetInstallNameDirForBuildTree(this->GetConfigName());
if (!install_name_dir.empty()) { if (target.HasSOName(cfgName))
vars["INSTALLNAME_DIR"] = {
this->GetLocalGenerator()->Convert(install_name_dir, vars["SONAME_FLAG"] = mf->GetSONameFlag(this->TargetLinkLanguage);
cmLocalGenerator::NONE, vars["SONAME"] = this->TargetNameSO;
cmLocalGenerator::SHELL, false); 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()) { if (!this->TargetNameImport.empty())
const std::string impLibPath = this->GetLocalGenerator() {
->ConvertToOutputFormat(targetOutputImplib, const std::string impLibPath = localGen.ConvertToOutputFormat(
cmLocalGenerator::SHELL); targetOutputImplib,
cmLocalGenerator::SHELL);
vars["TARGET_IMPLIB"] = impLibPath; vars["TARGET_IMPLIB"] = impLibPath;
EnsureParentDirectoryExists(impLibPath); EnsureParentDirectoryExists(impLibPath);
} }
if (!this->SetMsvcTargetPdbVariable(vars)) if (!this->SetMsvcTargetPdbVariable(vars))
{ {
@ -507,11 +523,13 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
std::string prefix; std::string prefix;
std::string base; std::string base;
std::string suffix; std::string suffix;
this->GetTarget()->GetFullNameComponents(prefix, base, suffix); target.GetFullNameComponents(prefix, base, suffix);
std::string dbg_suffix = ".dbg"; std::string dbg_suffix = ".dbg";
// TODO: Where to document? // TODO: Where to document?
if (mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX")) if (mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX"))
{
dbg_suffix = mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX"); dbg_suffix = mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX");
}
vars["TARGET_PDB"] = base + suffix + dbg_suffix; vars["TARGET_PDB"] = base + suffix + dbg_suffix;
} }
@ -528,9 +546,9 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
} }
const std::vector<cmCustomCommand> *cmdLists[3] = { const std::vector<cmCustomCommand> *cmdLists[3] = {
&this->GetTarget()->GetPreBuildCommands(), &target.GetPreBuildCommands(),
&this->GetTarget()->GetPreLinkCommands(), &target.GetPreLinkCommands(),
&this->GetTarget()->GetPostBuildCommands() &target.GetPostBuildCommands()
}; };
std::vector<std::string> preLinkCmdLines, postBuildCmdLines; std::vector<std::string> preLinkCmdLines, postBuildCmdLines;
@ -540,100 +558,97 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
&postBuildCmdLines &postBuildCmdLines
}; };
for (unsigned i = 0; i != 3; ++i) { for (unsigned i = 0; i != 3; ++i)
{
for (std::vector<cmCustomCommand>::const_iterator for (std::vector<cmCustomCommand>::const_iterator
ci = cmdLists[i]->begin(); ci = cmdLists[i]->begin();
ci != cmdLists[i]->end(); ++ci) { ci != cmdLists[i]->end(); ++ci)
cmCustomCommandGenerator ccg(*ci, this->GetConfigName(), mf); {
this->GetLocalGenerator()->AppendCustomCommandLines(ccg, cmCustomCommandGenerator ccg(*ci, cfgName, mf);
*cmdLineLists[i]); localGen.AppendCustomCommandLines(ccg, *cmdLineLists[i]);
}
} }
}
// If we have any PRE_LINK commands, we need to go back to HOME_OUTPUT for // If we have any PRE_LINK commands, we need to go back to HOME_OUTPUT for
// the link commands. // the link commands.
if (!preLinkCmdLines.empty()) { if (!preLinkCmdLines.empty())
const std::string homeOutDir = this->GetLocalGenerator() {
->ConvertToOutputFormat(mf->GetHomeOutputDirectory(), const std::string homeOutDir = localGen.ConvertToOutputFormat(
cmLocalGenerator::SHELL); mf->GetHomeOutputDirectory(),
cmLocalGenerator::SHELL);
preLinkCmdLines.push_back("cd " + homeOutDir); preLinkCmdLines.push_back("cd " + homeOutDir);
} }
vars["PRE_LINK"] = vars["PRE_LINK"] = localGen.BuildCommandLine(preLinkCmdLines);
this->GetLocalGenerator()->BuildCommandLine(preLinkCmdLines); std::string postBuildCmdLine = localGen.BuildCommandLine(postBuildCmdLines);
std::string postBuildCmdLine =
this->GetLocalGenerator()->BuildCommandLine(postBuildCmdLines);
cmNinjaVars symlinkVars; cmNinjaVars symlinkVars;
if (targetOutput == targetOutputReal) { if (targetOutput == targetOutputReal)
{
vars["POST_BUILD"] = postBuildCmdLine; vars["POST_BUILD"] = postBuildCmdLine;
} else { }
else
{
vars["POST_BUILD"] = ":"; vars["POST_BUILD"] = ":";
symlinkVars["POST_BUILD"] = postBuildCmdLine; symlinkVars["POST_BUILD"] = postBuildCmdLine;
} }
int linkRuleLength = this->GetGlobalGenerator()-> cmGlobalNinjaGenerator& globalGen = *this->GetGlobalGenerator();
GetRuleCmdLength(this->LanguageLinkerRule());
int commandLineLengthLimit = 1; int commandLineLengthLimit = 1;
const char* forceRspFile = "CMAKE_NINJA_FORCE_RESPONSE_FILE"; const char* forceRspFile = "CMAKE_NINJA_FORCE_RESPONSE_FILE";
if (!mf->IsDefinitionSet(forceRspFile) && if (!mf->IsDefinitionSet(forceRspFile) &&
cmSystemTools::GetEnv(forceRspFile) == 0) { cmSystemTools::GetEnv(forceRspFile) == 0)
#ifdef _WIN32 {
commandLineLengthLimit = 8000 - linkRuleLength; commandLineLengthLimit = calculateCommandLineLengthLimit(
#elif defined(__linux) || defined(__APPLE__) || defined(__HAIKU__) globalGen.GetRuleCmdLength(this->LanguageLinkerRule()));
// for instance ARG_MAX is 2096152 on Ubuntu or 262144 on Mac }
commandLineLengthLimit = ((int)sysconf(_SC_ARG_MAX))-linkRuleLength-1000;
#else
(void)linkRuleLength;
commandLineLengthLimit = -1;
#endif
}
//Get the global generator as we are going to be call WriteBuild numerous const std::string rspfile =
//times in the following section std::string(cmake::GetCMakeFilesDirectoryPostSlash())
cmGlobalNinjaGenerator* globalGenerator = this->GetGlobalGenerator(); + target.GetName() + ".rsp";
const std::string rspfile = std::string
(cmake::GetCMakeFilesDirectoryPostSlash()) +
this->GetTarget()->GetName() + ".rsp";
// Write the build statement for this target. // Write the build statement for this target.
globalGenerator->WriteBuild(this->GetBuildFileStream(), globalGen.WriteBuild(this->GetBuildFileStream(),
comment.str(), comment.str(),
this->LanguageLinkerRule(), this->LanguageLinkerRule(),
outputs, outputs,
explicitDeps, explicitDeps,
implicitDeps, implicitDeps,
emptyDeps, emptyDeps,
vars, vars,
rspfile, rspfile,
commandLineLengthLimit); commandLineLengthLimit);
if (targetOutput != targetOutputReal && if (targetOutput != targetOutputReal && !target.IsFrameworkOnApple())
!this->GetTarget()->IsFrameworkOnApple()) { {
if (targetType == cmTarget::EXECUTABLE) { if (targetType == cmTarget::EXECUTABLE)
globalGenerator->WriteBuild(this->GetBuildFileStream(), {
"Create executable symlink " + targetOutput, globalGen.WriteBuild(this->GetBuildFileStream(),
"CMAKE_SYMLINK_EXECUTABLE", "Create executable symlink " + targetOutput,
cmNinjaDeps(1, targetOutput), "CMAKE_SYMLINK_EXECUTABLE",
cmNinjaDeps(1, targetOutputReal), cmNinjaDeps(1, targetOutput),
emptyDeps, cmNinjaDeps(1, targetOutputReal),
emptyDeps, emptyDeps,
symlinkVars); emptyDeps,
} else { symlinkVars);
}
else
{
cmNinjaDeps symlinks; cmNinjaDeps symlinks;
const std::string soName = this->GetTargetFilePath(this->TargetNameSO); const std::string soName = this->GetTargetFilePath(this->TargetNameSO);
// If one link has to be created. // If one link has to be created.
if (targetOutputReal == soName || targetOutput == soName) { if (targetOutputReal == soName || targetOutput == soName)
{
symlinkVars["SONAME"] = soName; symlinkVars["SONAME"] = soName;
} else { }
else
{
symlinkVars["SONAME"] = ""; symlinkVars["SONAME"] = "";
symlinks.push_back(soName); symlinks.push_back(soName);
} }
symlinks.push_back(targetOutput); symlinks.push_back(targetOutput);
globalGenerator->WriteBuild(this->GetBuildFileStream(), globalGen.WriteBuild(this->GetBuildFileStream(),
"Create library symlink " + targetOutput, "Create library symlink " + targetOutput,
"CMAKE_SYMLINK_LIBRARY", "CMAKE_SYMLINK_LIBRARY",
symlinks, symlinks,
@ -641,23 +656,22 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
emptyDeps, emptyDeps,
emptyDeps, emptyDeps,
symlinkVars); symlinkVars);
}
} }
}
if (!this->TargetNameImport.empty()) { if (!this->TargetNameImport.empty())
{
// Since using multiple outputs would mess up the $out variable, use an // Since using multiple outputs would mess up the $out variable, use an
// alias for the import library. // alias for the import library.
globalGenerator->WritePhonyBuild(this->GetBuildFileStream(), globalGen.WritePhonyBuild(this->GetBuildFileStream(),
"Alias for import library.", "Alias for import library.",
cmNinjaDeps(1, targetOutputImplib), cmNinjaDeps(1, targetOutputImplib),
cmNinjaDeps(1, targetOutputReal)); cmNinjaDeps(1, targetOutputReal));
} }
// Add aliases for the file name and the target name. // Add aliases for the file name and the target name.
globalGenerator->AddTargetAlias(this->TargetNameOut, globalGen.AddTargetAlias(this->TargetNameOut, &target);
this->GetTarget()); globalGen.AddTargetAlias(this->GetTargetName(), &target);
globalGenerator->AddTargetAlias(this->GetTargetName(),
this->GetTarget());
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------