Share -v flag with clang, and use it during startup to log info about header search paths.

Also fix trying to report why compiler invocation failed when it was never attempted.
Add message about build being probably being configured incorrectly.

Signed-off-by: Vassil Vassilev <vvasilev@cern.ch>
This commit is contained in:
Frederich Munch 2016-08-16 18:05:45 -04:00 committed by sftnight
parent e1c400d627
commit bbfd61d897
6 changed files with 145 additions and 40 deletions

View File

@ -43,6 +43,7 @@ namespace cling {
bool NoCXXInc;
bool StdVersion;
bool StdLib;
bool Verbose;
///\brief The remaining arguments to pass to clang.
///
@ -65,8 +66,8 @@ namespace cling {
bool ErrorOut;
bool NoLogo;
bool ShowVersion;
bool Verbose;
bool Help;
bool Verbose() const { return CompilerOpts.Verbose; }
static void PrintHelp();
};

View File

@ -39,13 +39,15 @@ namespace cling {
/// \param [out] Paths - All the paths in the string that exist
/// \param [in] Mode - If any path doesn't exist stop and return false
/// \param [in] Delim - The delimeter to use
/// \param [in] Verbose - Whether to print out details as 'clang -v' would
///
/// \return true if all paths existed, otherwise false
///
bool SplitPaths(llvm::StringRef PathStr,
llvm::SmallVectorImpl<llvm::StringRef>& Paths,
SplitMode Mode = kPruneNonExistant,
llvm::StringRef Delim = llvm::StringRef(":"));
llvm::StringRef Delim = llvm::StringRef(":"),
bool Verbose = false);
///\brief Adds multiple include paths separated by a delimter into the
/// given HeaderSearchOptions. This adds the paths but does no further
@ -60,6 +62,11 @@ namespace cling {
clang::HeaderSearchOptions& Opts,
const char* Delim = ":");
///\brief Write to llvm::errs that directory does not exist in a format
/// matching what 'clang -v' would do
///
void LogNonExistantDirectory(llvm::StringRef Path);
///\brief Copies the current include paths into the HeaderSearchOptions.
///
///\param[in] Opts - HeaderSearchOptions to read from

View File

@ -359,7 +359,7 @@ static bool getISysRootVersion(const std::string& SDKs, int major,
return false;
}
static bool getISysRoot(std::string& sysRoot) {
static bool getISysRoot(std::string& sysRoot, bool Verbose) {
using namespace llvm::sys;
// Some versions of OS X and Server have headers installed
@ -408,12 +408,18 @@ static bool getISysRoot(std::string& sysRoot) {
if (majorVersion != -1 && minorVersion != -1) {
if (getISysRootVersion(SDKs, majorVersion, minorVersion, sysRoot))
return true;
if (Verbose)
llvm::errs() << "SDK version matching current OSX not found\n";
}
}
#define GET_ISYSROOT_VER(maj, min) \
if (getISysRootVersion(SDKs, maj, min, sysRoot)) \
return true;
return true; \
if (Verbose) \
llvm::errs() << "SDK version matching " << maj << "." << min \
<< " not found (this is what cling was compiled with)\n";
// Try to get the SDK for whatever cling was compiled with
#if defined(MAC_OS_X_VERSION_10_11)
@ -495,7 +501,8 @@ namespace {
static void ReadCompilerIncludePaths(const char* Compiler,
llvm::SmallVectorImpl<char>& Buf,
AdditionalArgList& Args) {
AdditionalArgList& Args,
bool Verbose) {
std::string CppInclQuery("LC_ALL=C ");
CppInclQuery.append(Compiler);
CppInclQuery.append(" -xc++ -E -v /dev/null 2>&1 >/dev/null "
@ -503,6 +510,9 @@ namespace {
"/{if (!/^#include </ && !/^End of search/){ print }}' "
"| GREP_OPTIONS= grep -E \"(c|g)\\+\\+\"");
if (Verbose)
llvm::errs() << "Looking for C++ headers with:\n " << CppInclQuery << "\n";
if (FILE *PF = ::popen(CppInclQuery.c_str(), "r")) {
Buf.resize(Buf.capacity_in_bytes());
while (fgets(&Buf[0], Buf.capacity_in_bytes(), PF) && Buf[0]) {
@ -510,28 +520,52 @@ namespace {
// Skip leading and trailing whitespace
Path = Path.trim();
if (!Path.empty()) {
if (llvm::sys::fs::is_directory(Path))
if (!llvm::sys::fs::is_directory(Path)) {
if (Verbose)
cling::utils::LogNonExistantDirectory(Path);
}
else
Args.addArgument("-I", Path.str());
}
}
::pclose(PF);
} else
llvm::errs() << "popen failed for '" << CppInclQuery << "'\n";
} else {
llvm::errs() << "popen failed";
// Don't be overly verbose, we already printed the command
if (!Verbose)
llvm::errs() << " for '" << CppInclQuery << "'\n";
}
// Return the query in Buf on failure
if (Args.empty()) {
Buf.resize(0);
Buf.insert(Buf.begin(), CppInclQuery.begin(), CppInclQuery.end());
} else if (Verbose) {
llvm::errs() << "Found:\n";
for (const auto& Arg : Args)
llvm::errs() << " " << Arg.second << "\n";
}
}
static bool AddCxxPaths(llvm::StringRef PathStr, AdditionalArgList& Args) {
static bool AddCxxPaths(llvm::StringRef PathStr, AdditionalArgList& Args,
bool Verbose) {
if (Verbose)
llvm::errs() << "Looking for C++ headers in \"" << PathStr << "\"\n";
llvm::SmallVector<llvm::StringRef, 6> Paths;
if (!utils::SplitPaths(PathStr, Paths, utils::kFailNonExistant))
if (!utils::SplitPaths(PathStr, Paths, utils::kFailNonExistant,
":", Verbose))
return false;
if (Verbose) {
llvm::errs() << "Found:\n";
for (llvm::StringRef Path : Paths)
llvm::errs() << " " << Path << "\n";
}
for (llvm::StringRef Path : Paths)
Args.addArgument("-I", Path.str());
return true;
}
@ -543,6 +577,7 @@ namespace {
const char* llvmdir, const CompilerOptions& opts) {
static AdditionalArgList sArguments;
if (sArguments.empty()) {
const bool Verbose = opts.Verbose;
#ifdef _MSC_VER
// Honor %INCLUDE%. It should know essential search paths with vcvarsall.bat.
if (const char *cl_include_dir = getenv("INCLUDE")) {
@ -606,35 +641,47 @@ namespace {
clang.append(" -stdlib=libstdc++");
#endif
}
ReadCompilerIncludePaths(clang.c_str(), buffer, sArguments);
ReadCompilerIncludePaths(clang.c_str(), buffer, sArguments, Verbose);
}
#endif // _LIBCPP_VERSION
// first try the include directory cling was built with
#ifdef CLING_CXX_INCL
if (sArguments.empty())
AddCxxPaths(CLING_CXX_INCL, sArguments);
AddCxxPaths(CLING_CXX_INCL, sArguments, Verbose);
#endif
// Then try the absolute path i.e.: '/usr/bin/g++'
#ifdef CLING_CXX_PATH
if (sArguments.empty())
ReadCompilerIncludePaths(CLING_CXX_PATH, buffer, sArguments);
ReadCompilerIncludePaths(CLING_CXX_PATH, buffer, sArguments, Verbose);
#endif
// Finally try the relative path 'g++'
#ifdef CLING_CXX_RLTV
if (sArguments.empty())
ReadCompilerIncludePaths(CLING_CXX_RLTV, buffer, sArguments);
ReadCompilerIncludePaths(CLING_CXX_RLTV, buffer, sArguments, Verbose);
#endif
if (sArguments.empty()) {
// buffer is a copy of the query string that failed
llvm::errs() << "ERROR in cling::CIFactory::createCI(): cannot extract "
"standard library include paths!\n"
"Invoking:\n"
" " << buffer.c_str() << "\n"
"results in\n";
int ExitCode = system(buffer.c_str());
llvm::errs() << "with exit code " << ExitCode << "\n";
llvm::errs() << "ERROR in cling::CIFactory::createCI(): cannot extract"
" standard library include paths!\n";
#if defined(CLING_CXX_PATH) || defined(CLING_CXX_RLTV)
// Only when ReadCompilerIncludePaths called do we have the command
// Verbose has already printed the command
if (!Verbose)
llvm::errs() << "Invoking:\n " << buffer.c_str() << "\n";
llvm::errs() << "Results was:\n";
const int ExitCode = system(buffer.c_str());
llvm::errs() << "With exit code " << ExitCode << "\n";
#elif !defined(CLING_CXX_INCL)
// Technically a valid configuration that just wants to use libClangs
// internal header detection, but for now give a hint about why.
llvm::errs() << "CLING_CXX_INCL, CLING_CXX_PATH, and CLING_CXX_RLTV"
" are undefined, there was probably an error during"
" configuration.\n"
#endif
} else
sArguments.addArgument("-nostdinc++");
}
@ -643,8 +690,11 @@ namespace {
if (!opts.NoBuiltinInc && !opts.SysRoot) {
std::string sysRoot;
if (getISysRoot(sysRoot))
if (getISysRoot(sysRoot, Verbose)) {
if (Verbose)
llvm::errs() << "Using SDK \"" << sysRoot << "\"\n";
sArguments.addArgument("-isysroot", std::move(sysRoot));
}
}
#if defined(__GLIBCXX__)
@ -875,9 +925,13 @@ namespace {
static void AddRuntimeIncludePaths(llvm::StringRef ClingBin,
clang::HeaderSearchOptions& HOpts) {
if (HOpts.Verbose)
llvm::errs() << "Adding runtime include paths:\n";
// Add configuration paths to interpreter's include files.
#ifdef CLING_INCLUDE_PATHS
utils::AddIncludePaths(CLING_INCLUDE_PATHS, HOpts);
if (HOpts.Verbose)
llvm::errs() << " \"" CLING_INCLUDE_PATHS "\"\n";
utils::AddIncludePaths(CLING_INCLUDE_PATHS, HOpts);
#endif
llvm::SmallString<512> P(ClingBin);
if (!P.empty()) {
@ -897,6 +951,10 @@ namespace {
createCIImpl(std::unique_ptr<llvm::MemoryBuffer> Buffer,
const CompilerOptions& COpts, const char* LLVMDir,
bool OnlyLex) {
// Follow clang -v convention of printing version on first line
if (COpts.Verbose)
llvm::errs() << "cling version " << ClingStringify(CLING_VERSION) << '\n';
// Create an instance builder, passing the LLVMDir and arguments.
//
@ -1139,6 +1197,10 @@ namespace {
if (CI->getHeaderSearchOpts().UseBuiltinIncludes)
AddRuntimeIncludePaths(ClingBin, HOpts);
// Write a marker to know the rest of the output is from clang
if (COpts.Verbose)
llvm::errs() << "Setting up system headers with clang:\n";
// ### FIXME:
// Want to update LLVM to 3.9 realease and better testing first, but
// ApplyHeaderSearchOptions shouldn't even be called here:

View File

@ -65,7 +65,6 @@ namespace {
Opts.ErrorOut = Args.hasArg(OPT__errorout);
Opts.NoLogo = Args.hasArg(OPT__nologo);
Opts.ShowVersion = Args.hasArg(OPT_version);
Opts.Verbose = Args.hasArg(OPT_v);
Opts.Help = Args.hasArg(OPT_help);
if (Args.hasArg(OPT__metastr, OPT__metastr_EQ)) {
Arg* MetaStringArg = Args.getLastArg(OPT__metastr, OPT__metastr_EQ);
@ -92,7 +91,7 @@ namespace {
CompilerOptions::CompilerOptions(int argc, const char* const* argv) :
Language(false), ResourceDir(false), SysRoot(false), NoBuiltinInc(false),
NoCXXInc(false), StdVersion(false), StdLib(false) {
NoCXXInc(false), StdVersion(false), StdLib(false), Verbose(false) {
if (argc && argv) {
// Preserve what's already in Remaining, the user might want to push args
// to clang while still using main's argc, argv
@ -127,6 +126,7 @@ void CompilerOptions::Parse(int argc, const char* const argv[],
case options::OPT_nobuiltininc: NoBuiltinInc = true; break;
// case options::OPT_nostdinc:
case options::OPT_nostdincxx: NoCXXInc = true; break;
case options::OPT_v: Verbose = true; break;
default:
if (Inputs && arg->getOption().getKind() == Option::InputClass)
@ -138,7 +138,7 @@ void CompilerOptions::Parse(int argc, const char* const argv[],
InvocationOptions::InvocationOptions(int argc, const char* const* argv) :
MetaString("."), ErrorOut(false), NoLogo(false), ShowVersion(false),
Verbose(false), Help(false) {
Help(false) {
ArrayRef<const char *> ArgStrings(argv, argv + argc);
unsigned MissingArgIndex, MissingArgCount;
@ -151,6 +151,10 @@ InvocationOptions::InvocationOptions(int argc, const char* const* argv) :
// Forward unknown arguments.
for (const Arg* arg : Args) {
switch (arg->getOption().getKind()) {
case Option::FlagClass:
// pass -v to clang as well
if (arg->getOption().getID() != OPT_v)
break;
case Option::UnknownClass:
case Option::InputClass:
// prune "-" we need to control where it appears when invoking clang

View File

@ -114,22 +114,42 @@ void DumpIncludePaths(const clang::HeaderSearchOptions& Opts,
}
}
void LogNonExistantDirectory(llvm::StringRef Path) {
llvm::errs() << " ignoring nonexistent directory \"" << Path << "\"\n";
}
bool SplitPaths(llvm::StringRef PathStr,
llvm::SmallVectorImpl<llvm::StringRef>& Paths,
SplitMode Mode,
llvm::StringRef Delim) {
SplitMode Mode, llvm::StringRef Delim, bool Verbose) {
bool AllExisted = true;
for (std::pair<llvm::StringRef, llvm::StringRef> Split = PathStr.split(Delim);
!Split.second.empty(); Split = PathStr.split(Delim)) {
if (!llvm::sys::fs::is_directory(Split.first)) {
if (Mode == kFailNonExistant)
return false;
AllExisted = false;
if (Mode == kAllowNonExistant)
Paths.push_back(Split.first);
} else
Paths.push_back(Split.first);
const bool Exists = llvm::sys::fs::is_directory(Split.first);
AllExisted = AllExisted && Exists;
if (!Exists) {
if (Mode == kFailNonExistant) {
if (Verbose) {
// Exiting early, but still log all non-existant paths that we have
LogNonExistantDirectory(Split.first);
while (!Split.second.empty()) {
Split = PathStr.split(Delim);
if (llvm::sys::fs::is_directory(Split.first)) {
llvm::errs() << " ignoring directory that exists \""
<< Split.first << "\"\n";
} else
LogNonExistantDirectory(Split.first);
Split = Split.second.split(Delim);
}
if (!llvm::sys::fs::is_directory(Split.first))
LogNonExistantDirectory(Split.first);
}
return false;
} else if (Verbose)
LogNonExistantDirectory(Split.first);
}
Paths.push_back(Split.first);
PathStr = Split.second;
}
@ -149,7 +169,7 @@ void AddIncludePaths(llvm::StringRef PathStr, clang::HeaderSearchOptions& HOpts,
llvm::SmallVector<llvm::StringRef, 10> Paths;
if (Delim && *Delim)
SplitPaths(PathStr, Paths, kAllowNonExistant, Delim);
SplitPaths(PathStr, Paths, kAllowNonExistant, Delim, HOpts.Verbose);
else
Paths.push_back(PathStr);
@ -170,6 +190,12 @@ void AddIncludePaths(llvm::StringRef PathStr, clang::HeaderSearchOptions& HOpts,
for (llvm::StringRef Path : PathsChecked)
HOpts.AddPath(Path, clang::frontend::Angled,
IsFramework, IsSysRootRelative);
if (HOpts.Verbose) {
llvm::errs() << "Added include paths:\n";
for (llvm::StringRef Path : PathsChecked)
llvm::errs() << " " << Path << "\n";
}
}
} // namespace utils

View File

@ -18,6 +18,7 @@ const char* argv[] = {
"FileToExecuteA",
"-isysroot",
"APAth",
"-nobuiltininc",
"-v",
"FileToExecuteB",
"-L/Path/To/Libs",
@ -31,12 +32,14 @@ COpts.Language
// CHECK: (bool) true
COpts.SysRoot
// CHECK: (bool) true
COpts.NoBuiltinInc
// CHECK: (bool) true
COpts.NoCXXInc
// CHECK: (bool) false
// library caller options: arguments passed as is
COpts.Remaining
// CHECK: {{.*}} { "progname", "-", "-xobjective-c", "FileToExecuteA", "-isysroot", "APAth", "-v", "FileToExecuteB", "-L/Path/To/Libs", "-lTest" }
// CHECK: {{.*}} { "progname", "-", "-xobjective-c", "FileToExecuteA", "-isysroot", "APAth", "-nobuiltininc", "-v", "FileToExecuteB", "-L/Path/To/Libs", "-lTest" }
argv[6] = "-nostdinc++";
cling::InvocationOptions IOpts(argc, argv);
@ -53,12 +56,14 @@ IOpts.CompilerOpts.Language
// CHECK: (bool) true
IOpts.CompilerOpts.SysRoot
// CHECK: (bool) true
IOpts.CompilerOpts.NoBuiltinInc
// CHECK: (bool) false
IOpts.CompilerOpts.NoCXXInc
// CHECK: (bool) true
// user options from main: filtered by cling (no '-')
IOpts.CompilerOpts.Remaining
// CHECK: {{.*}} { "progname", "-xobjective-c", "FileToExecuteA", "-isysroot", "APAth", "-nostdinc++", "FileToExecuteB" }
// CHECK: {{.*}} { "progname", "-xobjective-c", "FileToExecuteA", "-isysroot", "APAth", "-nostdinc++", "-v", "FileToExecuteB" }
// expected-no-diagnostics
.q