ui: Added user interface for auto system header search paths detection

* moved detection files to lib_gui
* added ui to global header search and framework search ui in project wizzard and preferences
* detecting the search paths will add them to the list if not added yet
* only detected compilers are shown in the dropdown list
This commit is contained in:
Eberhard Graether
2016-04-06 11:23:20 +02:00
parent 93f21283f6
commit 5e6714d95a
26 changed files with 345 additions and 243 deletions
+12
View File
@@ -151,4 +151,16 @@ add_files(
qt/QtApplication.h
qt/QtCoreApplication.cpp
qt/QtCoreApplication.h
utility/headerSearch/CompilerDetector.cpp
utility/headerSearch/CompilerDetector.h
utility/headerSearch/DetectorBase.cpp
utility/headerSearch/DetectorBase.h
utility/headerSearch/StandardHeaderDetection.cpp
utility/headerSearch/StandardHeaderDetection.h
utility/headerSearch/VisualStudioDetector.cpp
utility/headerSearch/VisualStudioDetector.h
utility/utilityApp.cpp
utility/utilityApp.h
)
@@ -92,7 +92,7 @@ void QtProjectWizzard::newProjectFromSolution(const std::string& ideId, const st
std::string title = "NEW PROJECT FROM ";
title += ideId;
title += " SOLUTION";
boost::algorithm::to_upper(title);
window->updateTitle(QString(title.c_str()));
@@ -232,8 +232,8 @@ QtProjectWizzardWindow* QtProjectWizzard::createWindowWithContent<QtProjectWizza
connect(window, SIGNAL(canceled()), this, SLOT(cancelWizzard()));
QtProjectWizzardContentSelect* content = new QtProjectWizzardContentSelect(&m_settings, window, m_parserManager);
window->setContent(content);
window->setup();
@@ -7,6 +7,7 @@
#include "qt/element/QtDirectoryListBox.h"
#include "settings/ApplicationSettings.h"
#include "utility/file/FileSystem.h"
#include "utility/headerSearch/StandardHeaderDetection.h"
#include "utility/utility.h"
QtProjectWizzardContentPaths::QtProjectWizzardContentPaths(ProjectSettings* settings, QtProjectWizzardWindow* window)
@@ -47,6 +48,11 @@ void QtProjectWizzardContentPaths::populateWindow(QGridLayout* layout, int& row)
addFilesButton(m_showFilesString, layout, row);
}
if (m_detectionString.size() > 0)
{
addDetection(m_detectionString, layout, row);
}
row++;
layout->setColumnStretch(QtProjectWizzardWindow::FRONT_COL, 1);
@@ -72,6 +78,12 @@ void QtProjectWizzardContentPaths::populateForm(QGridLayout* layout, int& row)
addFilesButton(m_showFilesString, layout, row);
row++;
}
if (m_detectionString.size() > 0)
{
addDetection(m_detectionString, layout, row);
row++;
}
}
QSize QtProjectWizzardContentPaths::preferredWindowSize() const
@@ -101,6 +113,60 @@ void QtProjectWizzardContentPaths::setHelpString(const QString& help)
m_helpString = help;
}
void QtProjectWizzardContentPaths::addDetection(QString name, QGridLayout* layout, int row)
{
StandardHeaderDetection detection;
std::vector<std::string> compilers = detection.getDetectedCompilers();
if (!compilers.size())
{
return;
}
QLabel* label = new QLabel("Auto detection from:");
m_detectorBox = new QComboBox();
for (const std::string& compiler : compilers)
{
m_detectorBox->addItem(compiler.c_str());
}
QPushButton* button = new QPushButton("detect");
button->setObjectName("windowButton");
connect(button, SIGNAL(clicked()), this, SLOT(detectionClicked()));
QHBoxLayout* hlayout = new QHBoxLayout();
hlayout->addWidget(label);
hlayout->addWidget(m_detectorBox);
hlayout->addWidget(button);
layout->addLayout(hlayout, row, QtProjectWizzardWindow::BACK_COL, Qt::AlignLeft | Qt::AlignTop);
}
void QtProjectWizzardContentPaths::detectionClicked()
{
StandardHeaderDetection detection;
std::vector<FilePath> paths;
if (m_detectionString == "headers")
{
paths = detection.getStandardHeaderPaths(m_detectorBox->currentText().toStdString());
}
else if (m_detectionString == "frameworks")
{
paths = detection.getStandardFrameworkPaths(m_detectorBox->currentText().toStdString());
}
std::vector<FilePath> oldPaths = m_list->getList();
std::set<FilePath> uniquePaths;
uniquePaths.insert(oldPaths.begin(), oldPaths.end());
uniquePaths.insert(paths.begin(), paths.end());
m_list->setList(utility::toVector(uniquePaths));
}
QtProjectWizzardContentPathsSource::QtProjectWizzardContentPathsSource(
ProjectSettings* settings, QtProjectWizzardWindow* window
)
@@ -291,14 +357,16 @@ QtProjectWizzardContentPathsHeaderSearchGlobal::QtProjectWizzardContentPathsHead
{
setInfo(
"Global Header Search Paths",
"These header search paths will be used in all your projects. Use it to add system header and Standard Library "
"header paths (See <a href=\"https://coati.io/documentation/#FindingSystemHeaderLocations\">Finding "
"System Header Locations</a>).",
"These header search paths will be used in all your projects. Use it to add system header paths "
"(See <a href=\"https://coati.io/documentation/#FindingSystemHeaderLocations\">Finding System Header Locations</a> "
"or use the auto detection below).",
"Header Search Paths define where additional headers, that your project depends on, are found. Usually they are "
"header files of frameworks or libraries that your project uses. These files won't be analyzed, but Coati needs "
"them for correct analysis.\n\n"
"Header Search Paths defined here will be used for all projects."
);
m_detectionString = "headers";
}
void QtProjectWizzardContentPathsHeaderSearchGlobal::load()
@@ -350,11 +418,13 @@ QtProjectWizzardContentPathsFrameworkSearchGlobal::QtProjectWizzardContentPathsF
"Global Framework Search Paths",
"These framework search paths will be used in all your projects. Use it to add system frameworks "
"(See <a href=\"https://coati.io/documentation/#FindingSystemHeaderLocations\">"
"Finding System Header Locations</a>).",
"Finding System Header Locations</a> or use the auto detection below).",
"Framework Search Paths define where MacOS framework containers (.framework), that your project depends on, are "
"found.\n\n"
"Framework Search Paths defined here will be used for all projects."
);
m_detectionString = "frameworks";
}
void QtProjectWizzardContentPathsFrameworkSearchGlobal::load()
@@ -1,6 +1,7 @@
#ifndef QT_PROJECT_WIZZARD_CONTENT_PATHS_H
#define QT_PROJECT_WIZZARD_CONTENT_PATHS_H
#include <QComboBox>
#include <QPushButton>
#include "qt/window/project_wizzard/QtProjectWizzardContent.h"
@@ -31,14 +32,22 @@ protected:
void setDescriptionString(const QString& description);
void setHelpString(const QString& help);
void addDetection(QString name, QGridLayout* layout, int row);
QtDirectoryListBox* m_list;
QString m_showFilesString;
QString m_detectionString;
private slots:
void detectionClicked();
private:
QString m_titleString;
QString m_descriptionString;
QString m_helpString;
QComboBox* m_detectorBox;
};
@@ -0,0 +1,62 @@
#include "utility/headerSearch/CompilerDetector.h"
#include "utility/utilityApp.h"
#include "utility/utilityString.h"
CompilerDetector::CompilerDetector(const std::string& name)
: DetectorBase(name)
{
}
CompilerDetector::~CompilerDetector()
{
}
std::vector<std::string> CompilerDetector::getHeaderPaths()
{
std::string command = m_name + " -x c++ -v -E /dev/null";
std::string clangOutput = utility::executeProcess(command.c_str());
std::string standardHeaders =
utility::substrBetween(clangOutput, "#include <...> search starts here:\n","\nEnd of search list");
std::vector<std::string> paths;
if (!standardHeaders.empty())
{
for (std::string s : utility::splitToVector(standardHeaders, '\n'))
{
paths.push_back(utility::trim(s));
}
}
return paths;
}
std::vector<FilePath> CompilerDetector::getStandardHeaderPaths()
{
std::vector<std::string> paths = getHeaderPaths();
std::vector<FilePath> headerPaths;
for (const std::string& path : paths)
{
if (!utility::isPostfix(" (framework directory)", path))
{
headerPaths.push_back(FilePath(path).canonical());
}
}
return headerPaths;
}
std::vector<FilePath> CompilerDetector::getStandardFrameworkPaths()
{
std::vector<std::string> paths = getHeaderPaths();
std::vector<FilePath> frameworkPaths;
for (const std::string& path : paths)
{
if (utility::isPostfix(" (framework directory)", path))
{
frameworkPaths.push_back(FilePath(utility::replace(path, " (framework directory)", "")).canonical());
}
}
return frameworkPaths;
}
@@ -0,0 +1,20 @@
#ifndef COMPILER_DETECTOR_H
#define COMPILER_DETECTOR_H
#include "utility/headerSearch/DetectorBase.h"
class CompilerDetector
: public DetectorBase
{
public:
CompilerDetector(const std::string& name);
virtual ~CompilerDetector();
std::vector<std::string> getHeaderPaths();
virtual std::vector<FilePath> getStandardHeaderPaths();
virtual std::vector<FilePath> getStandardFrameworkPaths();
};
#endif // COMPILER_DETECTOR_H
@@ -0,0 +1,29 @@
#include "utility/headerSearch/DetectorBase.h"
DetectorBase::DetectorBase(const std::string name)
{
setName(name);
}
bool DetectorBase::detect()
{
return !getStandardHeaderPaths().empty();
}
std::vector<FilePath> DetectorBase::getStandardFrameworkPaths()
{
return std::vector<FilePath>();
}
std::string DetectorBase::getName() const
{
return m_name;
}
void DetectorBase::setName(const std::string& name)
{
if (!name.empty())
{
m_name = name;
}
}
@@ -0,0 +1,22 @@
#ifndef DETECTOR_BASE_H
#define DETECTOR_BASE_H
#include <vector>
#include "utility/file/FilePath.h"
class DetectorBase
{
public:
DetectorBase(const std::string name);
virtual ~DetectorBase(){};
virtual bool detect();
virtual std::vector<FilePath> getStandardHeaderPaths() = 0;
virtual std::vector<FilePath> getStandardFrameworkPaths();
virtual std::string getName() const;
virtual void setName(const std::string& name);
protected:
std::string m_name;
};
#endif // DETECTOR_BASE_H
@@ -0,0 +1,106 @@
#include "utility/headerSearch/StandardHeaderDetection.h"
#include <cstdlib>
#include <iostream>
#include <map>
#include <string>
#include <utility>
#include <vector>
#include "utility/file/FilePath.h"
#include "utility/headerSearch/CompilerDetector.h"
#include "utility/headerSearch/VisualStudioDetector.h"
#include "utility/logging/logging.h"
#include "utility/utilityApp.h"
#include "utility/utilityString.h"
StandardHeaderDetection::DetectorMap StandardHeaderDetection::s_availableDetectors;
StandardHeaderDetection::DetectorMap StandardHeaderDetection::s_detectedCompilers;
StandardHeaderDetection::StandardHeaderDetection()
{
if (!s_availableDetectors.size())
{
addDetector(std::make_shared<CompilerDetector>("gcc"));
addDetector(std::make_shared<CompilerDetector>("clang"));
addDetector(std::make_shared<VisualStudioDetector>("14"));
addDetector(std::make_shared<VisualStudioDetector>("12"));
addDetector(std::make_shared<VisualStudioDetector>("11"));
addDetector(std::make_shared<VisualStudioDetector>("9"));
detectHeaders();
}
}
StandardHeaderDetection::~StandardHeaderDetection()
{
}
void StandardHeaderDetection::addDetector(std::shared_ptr<DetectorBase> detector)
{
s_availableDetectors.emplace(detector->getName(), detector);
}
void StandardHeaderDetection::detectHeaders()
{
for ( DetectorPair detector : s_availableDetectors)
{
if ( detector.second->detect() )
{
s_detectedCompilers.insert(detector);
}
}
}
std::vector<std::string> StandardHeaderDetection::getDetectedCompilers()
{
std::vector<std::string> v;
for ( DetectorPair detector : s_detectedCompilers)
{
v.push_back(detector.first);
}
return v;
}
std::vector<FilePath> StandardHeaderDetection::getStandardHeaderPaths(std::string compiler)
{
auto it = s_detectedCompilers.find(compiler);
if (it != s_detectedCompilers.end())
{
return it->second->getStandardHeaderPaths();
}
return std::vector<FilePath>();
}
std::vector<FilePath> StandardHeaderDetection::getStandardFrameworkPaths(std::string compiler)
{
auto it = s_detectedCompilers.find(compiler);
if (it != s_detectedCompilers.end())
{
return it->second->getStandardFrameworkPaths();
}
return std::vector<FilePath>();
}
void StandardHeaderDetection::printDetectedCompilers()
{
std::cout << "Detected Compilers: " << std::endl;
std::vector<std::string> compilers = getDetectedCompilers();
for ( std::string compiler : compilers)
{
std::cout << compiler << std::endl;
}
}
void StandardHeaderDetection::printAvailableDetectors()
{
std::cout << "Available Detectors: " << std::endl;
for ( DetectorPair detector : s_availableDetectors)
{
std::cout << detector.first << std::endl;
}
}
@@ -0,0 +1,43 @@
#ifndef STANDARD_HEADER_DETECTION_H
#define STANDARD_HEADER_DETECTION_H
#include <map>
#include <memory>
#include <string>
#include <iostream>
#include "utility/headerSearch/DetectorBase.h"
class FilePath;
class StandardHeaderDetection
{
public:
StandardHeaderDetection();
~StandardHeaderDetection();
void addDetector(std::shared_ptr<DetectorBase> detector);
/// Checks all availabe detectors and saves found Compilers
void detectHeaders();
/// Returns alls found compilers
std::vector<std::string> getDetectedCompilers();
/// Returns the headerpaths from a found compiler
std::vector<FilePath> getStandardHeaderPaths(std::string compiler);
std::vector<FilePath> getStandardFrameworkPaths(std::string compiler);
/// Debugging Output
void printAvailableDetectors();
void printDetectedCompilers();
private:
typedef std::map<std::string, std::shared_ptr<DetectorBase>> DetectorMap;
typedef std::pair<std::string, std::shared_ptr<DetectorBase>> DetectorPair;
static DetectorMap s_availableDetectors;
static DetectorMap s_detectedCompilers;
};
#endif // STANDARD_HEADER_DETECTION_H
@@ -0,0 +1,117 @@
#include "utility/headerSearch/VisualStudioDetector.h"
#include <string>
#include <QSettings>
#include <QSysInfo>
#include <QDir>
#include "utility/file/FilePath.h"
#include "utility/logging/logging.h"
VisualStudioDetector::VisualStudioDetector(const std::string name)
: DetectorBase("")
, m_isExpress(false)
{
setName(name);
}
VisualStudioDetector::~VisualStudioDetector()
{
}
void VisualStudioDetector::setName(const std::string& version)
{
m_versionNumber = std::stoi(version);
if (m_versionNumber > 8 && m_versionNumber < 15)
{
DetectorBase::setName("VS" + version + "0");
}
else
{
// unsupported Visual Studio version
}
}
std::string VisualStudioDetector::getFullName()
{
return "Visual Studio " + std::to_string(m_versionNumber + 1) + (m_isExpress ? " Express" : "");
}
std::vector<FilePath> VisualStudioDetector::getStandardHeaderPaths()
{
std::vector<FilePath> headerPaths;
// vc++ headers
if ( !getStanardHeaderPathsUsingEnvironmentVariable(headerPaths) )
{
if ( !getStanardHeaderPathsUsingRegistry(headerPaths) )
{
if ( !getStanardHeaderPathsUsingRegistry(headerPaths, true) )
{
return headerPaths;
}
}
}
//windows sdk
//TODO
return headerPaths;
}
std::string getInstallDir(const std::string RegistryKey)
{
return "";
}
std::string getWindowsSDKDir()
{
return "";
}
bool VisualStudioDetector::getStanardHeaderPathsUsingEnvironmentVariable(std::vector<FilePath>& paths)
{
std::string VSToolstring = m_name + "comntools";
std::vector<FilePath> path;
if ( const char* vs_env = std::getenv(VSToolstring.c_str()))
{
FilePath VSHeaderpath(vs_env);
VSHeaderpath = VSHeaderpath.concat("../vc/include");
if (VSHeaderpath.exists())
{
LOG_INFO_STREAM(<< getFullName() << " includes detected");
path.push_back(VSHeaderpath.str());
paths = std::move(path);
return true;
}
}
return false;
}
bool VisualStudioDetector::getStanardHeaderPathsUsingRegistry(std::vector<FilePath>& paths, bool lookForExpressVersion)
{
QString key = "HKEY_LOCAL_MACHINE\\SOFTWARE\\";
if (QSysInfo::currentCpuArchitecture() == "x86_64")
{
key += "Wow6432Node\\";
}
key += "Microsoft\\";
key += ( lookForExpressVersion ? "VCExpress" : "VisualStudio" );
key += "\\" + QString::number(m_versionNumber) + ".0";
QSettings expressKey(key, QSettings::NativeFormat);
QString value = expressKey.value("InstallDir").toString() + "../VC/include";
QDir dir(value);
if ( dir.exists())
{
if ( lookForExpressVersion )
{
m_isExpress = true;
}
return true;
}
return false;
}
@@ -0,0 +1,26 @@
#ifndef VISUAL_STUDIO_DETECTOR_H
#define VISUAL_STUDIO_DETECTOR_H
#include <vector>
#include "utility/headerSearch/DetectorBase.h"
class FilePath;
class VisualStudioDetector : public DetectorBase
{
public:
VisualStudioDetector(const std::string name = "14");
virtual ~VisualStudioDetector();
virtual std::vector<FilePath> getStandardHeaderPaths();
private:
std::string getFullName();
bool getStanardHeaderPathsUsingEnvironmentVariable(std::vector<FilePath>& paths);
bool getStanardHeaderPathsUsingRegistry(std::vector<FilePath>& paths, bool lookForExpressVersion = false);
void setName(const std::string& version);
int m_versionNumber;
bool m_isExpress;
};
#endif // VISUAL_STUDIO_DETECTOR_H
+15
View File
@@ -0,0 +1,15 @@
#include "utility/utilityApp.h"
#include <QProcess>
std::string utility::executeProcess(const char *cmd)
{
QProcess process;
process.setProcessChannelMode(QProcess::MergedChannels);
process.start(cmd);
process.waitForFinished();
std::string processoutput = process.readAll().toStdString();
process.close();
return processoutput;
}
+13
View File
@@ -0,0 +1,13 @@
#ifndef UTILITY_APP_H
#define UTILITY_APP_H
#include <QProcess>
namespace utility
{
std::string executeProcess(const char* cmd);
}
#endif // UTILITY_APP_H