summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorBill Hoffman <bill.hoffman@kitware.com>2016-06-02 22:08:30 (GMT)
committerBrad King <brad.king@kitware.com>2016-06-17 14:56:40 (GMT)
commit96242f8022fa4bc718ef36cda43f5dfe6236c066 (patch)
treeeb344591def11380b95fba62e71aa950e3671b87 /Source
parentba92e11f8b461513566d5cc3c0b53b2215bb85f7 (diff)
downloadCMake-96242f8022fa4bc718ef36cda43f5dfe6236c066.zip
CMake-96242f8022fa4bc718ef36cda43f5dfe6236c066.tar.gz
CMake-96242f8022fa4bc718ef36cda43f5dfe6236c066.tar.bz2
Add options to run `ldd -u -r` as a "link-what-you-use" tool
Create a LINK_WHAT_YOU_USE target property and corresponding CMAKE_LINK_WHAT_YOU_USE variable to enable this behavior. Extend link commands by running `ldd -u -r` to detect shared libraries that are linked but not needed.
Diffstat (limited to 'Source')
-rw-r--r--Source/cmMakefileExecutableTargetGenerator.cxx12
-rw-r--r--Source/cmMakefileLibraryTargetGenerator.cxx13
-rw-r--r--Source/cmNinjaNormalTargetGenerator.cxx24
-rw-r--r--Source/cmTarget.cxx1
-rw-r--r--Source/cmcmd.cxx35
5 files changed, 79 insertions, 6 deletions
diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx
index 9d42257..ba4c6e6 100644
--- a/Source/cmMakefileExecutableTargetGenerator.cxx
+++ b/Source/cmMakefileExecutableTargetGenerator.cxx
@@ -187,6 +187,9 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
this->LocalGenerator->AppendFlags(
linkFlags, this->Makefile->GetDefinition(export_flag_var));
}
+ if (this->GeneratorTarget->GetProperty("LINK_WHAT_YOU_USE")) {
+ this->LocalGenerator->AppendFlags(linkFlags, " -Wl,--no-as-needed");
+ }
// Add language feature flags.
this->AddFeatureFlags(flags, linkLanguage);
@@ -356,6 +359,15 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
vars.LinkFlags = linkFlags.c_str();
vars.Manifests = manifests.c_str();
+ if (this->GeneratorTarget->GetProperty("LINK_WHAT_YOU_USE")) {
+ std::string cmakeCommand =
+ this->Convert(cmSystemTools::GetCMakeCommand(), cmLocalGenerator::NONE,
+ cmLocalGenerator::SHELL);
+ cmakeCommand += " -E __run_iwyu --lwyu=";
+ cmakeCommand += targetOutPathReal;
+ real_link_commands.push_back(cmakeCommand);
+ }
+
// Expand placeholders in the commands.
this->LocalGenerator->TargetImplib = targetOutPathImport;
for (std::vector<std::string>::iterator i = real_link_commands.begin();
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx
index 128291d..6666c36 100644
--- a/Source/cmMakefileLibraryTargetGenerator.cxx
+++ b/Source/cmMakefileLibraryTargetGenerator.cxx
@@ -163,6 +163,9 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink)
extraFlags, "CMAKE_SHARED_LINKER_FLAGS", this->ConfigName);
this->AddModuleDefinitionFlag(extraFlags);
+ if (this->GeneratorTarget->GetProperty("LINK_WHAT_YOU_USE")) {
+ this->LocalGenerator->AppendFlags(extraFlags, " -Wl,--no-as-needed");
+ }
this->WriteLibraryRules(linkRuleVar, extraFlags, relink);
}
@@ -682,6 +685,15 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
// Get the set of commands.
std::string linkRule = this->GetLinkRule(linkRuleVar);
cmSystemTools::ExpandListArgument(linkRule, real_link_commands);
+ if (this->GeneratorTarget->GetProperty("LINK_WHAT_YOU_USE") &&
+ (this->GeneratorTarget->GetType() == cmState::SHARED_LIBRARY)) {
+ std::string cmakeCommand =
+ this->Convert(cmSystemTools::GetCMakeCommand(),
+ cmLocalGenerator::NONE, cmLocalGenerator::SHELL);
+ cmakeCommand += " -E __run_iwyu --lwyu=";
+ cmakeCommand += targetOutPathReal;
+ real_link_commands.push_back(cmakeCommand);
+ }
// Expand placeholders.
for (std::vector<std::string>::iterator i = real_link_commands.begin();
@@ -728,6 +740,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
commands.insert(commands.end(), commands1.begin(), commands1.end());
commands1.clear();
}
+
// Add the post-build rules when building but not when relinking.
if (!relink) {
this->LocalGenerator->AppendCustomCommands(
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index 3e91545..7c18414 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -295,6 +295,22 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd()
const char* linkCmd = mf->GetDefinition(linkCmdVar);
if (linkCmd) {
cmSystemTools::ExpandListArgument(linkCmd, linkCmds);
+ if (this->GetGeneratorTarget()->GetProperty("LINK_WHAT_YOU_USE")) {
+ std::string cmakeCommand =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
+ cmakeCommand += " -E __run_iwyu --lwyu=";
+ cmGeneratorTarget& gt = *this->GetGeneratorTarget();
+ const std::string cfgName = this->GetConfigName();
+ std::string targetOutput = ConvertToNinjaPath(gt.GetFullPath(cfgName));
+ std::string targetOutputReal =
+ this->ConvertToNinjaPath(gt.GetFullPath(cfgName,
+ /*implib=*/false,
+ /*realpath=*/true));
+ cmakeCommand += targetOutputReal;
+ cmakeCommand += " || true";
+ linkCmds.push_back(cmakeCommand);
+ }
return linkCmds;
}
}
@@ -467,6 +483,10 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
vars["MANIFESTS"] = this->GetManifests();
vars["LINK_PATH"] = frameworkPath + linkPath;
+ std::string lwyuFlags;
+ if (genTarget.GetProperty("LINK_WHAT_YOU_USE")) {
+ lwyuFlags = " -Wl,--no-as-needed";
+ }
// Compute architecture specific link flags. Yes, these go into a different
// variable for executables, probably due to a mistake made when duplicating
@@ -474,16 +494,17 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
if (targetType == cmState::EXECUTABLE) {
std::string t = vars["FLAGS"];
localGen.AddArchitectureFlags(t, &genTarget, TargetLinkLanguage, cfgName);
+ t += lwyuFlags;
vars["FLAGS"] = t;
} else {
std::string t = vars["ARCH_FLAGS"];
localGen.AddArchitectureFlags(t, &genTarget, TargetLinkLanguage, cfgName);
vars["ARCH_FLAGS"] = t;
t = "";
+ t += lwyuFlags;
localGen.AddLanguageFlags(t, TargetLinkLanguage, cfgName);
vars["LANGUAGE_COMPILE_FLAGS"] = t;
}
-
if (this->GetGeneratorTarget()->HasSOName(cfgName)) {
vars["SONAME_FLAG"] = mf->GetSONameFlag(this->TargetLinkLanguage);
vars["SONAME"] = this->TargetNameSO;
@@ -607,7 +628,6 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
vars["POST_BUILD"] = ":";
symlinkVars["POST_BUILD"] = postBuildCmdLine;
}
-
cmGlobalNinjaGenerator& globalGen = *this->GetGlobalGenerator();
int commandLineLengthLimit = -1;
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index f435a1d..8327af2 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -139,6 +139,7 @@ void cmTarget::SetMakefile(cmMakefile* mf)
this->SetPropertyDefault("C_CLANG_TIDY", 0);
this->SetPropertyDefault("C_COMPILER_LAUNCHER", 0);
this->SetPropertyDefault("C_INCLUDE_WHAT_YOU_USE", 0);
+ this->SetPropertyDefault("LINK_WHAT_YOU_USE", 0);
this->SetPropertyDefault("C_STANDARD", 0);
this->SetPropertyDefault("C_STANDARD_REQUIRED", 0);
this->SetPropertyDefault("C_EXTENSIONS", 0);
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 535dead..161256e 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -271,6 +271,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
std::string iwyu;
std::string tidy;
std::string sourceFile;
+ std::string lwyu;
for (std::string::size_type cc = 2; cc < args.size(); cc++) {
std::string const& arg = args[cc];
if (arg == "--") {
@@ -281,6 +282,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
tidy = arg.substr(7);
} else if (doing_options && cmHasLiteralPrefix(arg, "--source=")) {
sourceFile = arg.substr(9);
+ } else if (doing_options && cmHasLiteralPrefix(arg, "--lwyu=")) {
+ lwyu = arg.substr(7);
} else if (doing_options) {
std::cerr << "__run_iwyu given unknown argument: " << arg << "\n";
return 1;
@@ -288,7 +291,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
orig_cmd.push_back(arg);
}
}
- if (tidy.empty() && iwyu.empty()) {
+ if (tidy.empty() && iwyu.empty() && lwyu.empty()) {
std::cerr << "__run_iwyu missing --tidy= or --iwyu=\n";
return 1;
}
@@ -296,7 +299,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
std::cerr << "__run_iwyu --tidy= requires --source=\n";
return 1;
}
- if (orig_cmd.empty()) {
+ if (orig_cmd.empty() && lwyu.empty()) {
std::cerr << "__run_iwyu missing compile command after --\n";
return 1;
}
@@ -345,13 +348,37 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
std::cerr << "Error running '" << tidy_cmd[0] << "'\n";
return 1;
}
-
// Output the stdout from clang-tidy to stderr
std::cerr << stdOut;
}
+ if (!lwyu.empty()) {
+ // Construct the ldd -r -u (link what you use lwyu) command line
+ // ldd -u -r lwuy target
+ std::vector<std::string> lwyu_cmd;
+ lwyu_cmd.push_back("ldd");
+ lwyu_cmd.push_back("-u");
+ lwyu_cmd.push_back("-r");
+ lwyu_cmd.push_back(lwyu);
+
+ // Run the ldd -u -r command line.
+ // Capture its stdout and hide its stderr.
+ std::string stdOut;
+ if (!cmSystemTools::RunSingleCommand(lwyu_cmd, &stdOut, 0, &ret, 0,
+ cmSystemTools::OUTPUT_NONE)) {
+ std::cerr << "Error running '" << lwyu_cmd[0] << "'\n";
+ return 1;
+ }
+ // Output the stdout from ldd -r -u to stderr
+ // Warn if lwyu reported anything.
+ if (stdOut.find("Unused direct dependencies:") != stdOut.npos) {
+ std::cerr << "Warning: " << stdOut;
+ }
+ }
+ ret = 0;
// Now run the real compiler command and return its result value.
- if (!cmSystemTools::RunSingleCommand(
+ if (lwyu.empty() &&
+ !cmSystemTools::RunSingleCommand(
orig_cmd, 0, 0, &ret, 0, cmSystemTools::OUTPUT_PASSTHROUGH)) {
std::cerr << "Error running '" << orig_cmd[0] << "'\n";
return 1;