2009-04-28 12:43:04 +02:00
/**************************************************************************
* *
* * This file is part of Qt Creator
* *
* * Copyright ( c ) 2009 Nokia Corporation and / or its subsidiary ( - ies ) .
* *
2009-06-17 00:01:27 +10:00
* * Contact : Nokia Corporation ( qt - info @ nokia . com )
2009-04-28 12:43:04 +02:00
* *
* * Commercial Usage
* *
* * Licensees holding valid Qt Commercial licenses may use this file in
* * accordance with the Qt Commercial License Agreement provided with the
* * Software or , alternatively , in accordance with the terms contained in
* * a written agreement between you and Nokia .
* *
* * GNU Lesser General Public License Usage
* *
* * Alternatively , this file may be used under the terms of the GNU Lesser
* * General Public License version 2.1 as published by the Free Software
* * Foundation and appearing in the file LICENSE . LGPL included in the
* * packaging of this file . Please review the following information to
* * ensure the GNU Lesser General Public License version 2.1 requirements
* * will be met : http : //www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
* *
* * If you are unsure which license is appropriate for your use , please
2009-08-14 09:30:56 +02:00
* * contact the sales department at http : //qt.nokia.com/contact.
2009-04-28 12:43:04 +02:00
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "debugginghelper.h"
2009-08-07 15:20:05 +02:00
2009-04-28 12:43:04 +02:00
# include <coreplugin/icore.h>
# include <QtCore/QFileInfo>
2009-08-07 15:20:05 +02:00
# include <QtCore/QCoreApplication>
2009-04-28 12:43:04 +02:00
# include <QtCore/QHash>
# include <QtCore/QProcess>
# include <QtCore/QDir>
# include <QtCore/QDateTime>
2009-08-07 15:20:05 +02:00
2009-04-28 12:43:04 +02:00
# include <QtGui/QDesktopServices>
using namespace ProjectExplorer ;
QString DebuggingHelperLibrary : : findSystemQt ( const Environment & env )
{
QStringList paths = env . path ( ) ;
foreach ( const QString & path , paths ) {
foreach ( const QString & possibleCommand , possibleQMakeCommands ( ) ) {
2009-08-07 15:20:05 +02:00
const QFileInfo qmake ( path + QLatin1Char ( ' / ' ) + possibleCommand ) ;
2009-04-28 12:43:04 +02:00
if ( qmake . exists ( ) ) {
if ( ! qtVersionForQMake ( qmake . absoluteFilePath ( ) ) . isNull ( ) ) {
return qmake . absoluteFilePath ( ) ;
}
}
}
}
return QString : : null ;
}
2009-09-03 19:16:22 +02:00
QStringList DebuggingHelperLibrary : : debuggingHelperLibraryDirectories ( const QString & qtInstallData )
2009-04-28 12:43:04 +02:00
{
2009-08-07 15:20:05 +02:00
const QChar slash = QLatin1Char ( ' / ' ) ;
2009-09-03 19:16:22 +02:00
const uint hash = qHash ( qtInstallData ) ;
2009-04-28 12:43:04 +02:00
QStringList directories ;
directories
2009-08-07 15:20:05 +02:00
< < ( qtInstallData + QLatin1String ( " /qtc-debugging-helper/ " ) )
< < QDir : : cleanPath ( ( QCoreApplication : : applicationDirPath ( ) + QLatin1String ( " /../qtc-debugging-helper/ " ) + QString : : number ( hash ) ) ) + slash
< < ( QDesktopServices : : storageLocation ( QDesktopServices : : DataLocation ) + QLatin1String ( " /qtc-debugging-helper/ " ) + QString : : number ( hash ) ) + slash ;
2009-04-28 12:43:04 +02:00
return directories ;
}
QString DebuggingHelperLibrary : : qtInstallDataDir ( const QString & qmakePath )
{
QProcess proc ;
2009-08-07 15:20:05 +02:00
proc . start ( qmakePath , QStringList ( ) < < QLatin1String ( " -query " ) < < QLatin1String ( " QT_INSTALL_DATA " ) ) ;
2009-04-28 12:43:04 +02:00
if ( proc . waitForFinished ( ) )
return QString ( proc . readAll ( ) . trimmed ( ) ) ;
return QString : : null ;
}
// Debugging Helper Library
2009-08-07 15:20:05 +02:00
static inline QString helperFilePath ( const QString & directory )
2009-07-15 17:41:45 +02:00
{
# if defined(Q_OS_WIN)
2009-08-07 15:20:05 +02:00
return directory + QLatin1String ( " debug/gdbmacros.dll " ) ;
2009-07-15 17:41:45 +02:00
# elif defined(Q_OS_MAC)
2009-08-07 15:20:05 +02:00
return directory + QLatin1String ( " libgdbmacros.dylib " ) ;
2009-07-15 17:41:45 +02:00
# else // generic UNIX
2009-08-07 15:20:05 +02:00
return directory + QLatin1String ( " libgdbmacros.so " ) ;
2009-07-15 17:41:45 +02:00
# endif
2009-08-07 15:20:05 +02:00
}
2009-09-03 19:16:22 +02:00
QStringList DebuggingHelperLibrary : : debuggingHelperLibraryLocationsByInstallData ( const QString & qtInstallData )
2009-08-07 15:20:05 +02:00
{
QStringList result ;
2009-09-03 19:16:22 +02:00
foreach ( const QString & directory , debuggingHelperLibraryDirectories ( qtInstallData ) )
2009-08-07 15:20:05 +02:00
result < < QFileInfo ( helperFilePath ( directory ) ) . filePath ( ) ;
2009-07-15 17:41:45 +02:00
return result ;
}
2009-09-03 19:16:22 +02:00
QString DebuggingHelperLibrary : : debuggingHelperLibraryByInstallData ( const QString & qtInstallData )
2009-04-28 12:43:04 +02:00
{
2009-09-17 15:47:28 +02:00
const QString dumperSourcePath = Core : : ICore : : instance ( ) - > resourcePath ( ) + QLatin1String ( " /gdbmacros/ " ) ;
QDateTime lastModified = QFileInfo ( dumperSourcePath + " gdbmacros.cpp " ) . lastModified ( ) ;
2009-09-03 19:16:22 +02:00
foreach ( const QString & directory , debuggingHelperLibraryDirectories ( qtInstallData ) ) {
2009-08-07 15:20:05 +02:00
const QFileInfo fi ( helperFilePath ( directory ) ) ;
2009-09-21 16:33:27 +02:00
if ( fi . exists ( ) & & fi . lastModified ( ) > = lastModified )
2009-04-28 12:43:04 +02:00
return fi . filePath ( ) ;
}
return QString ( ) ;
}
QString DebuggingHelperLibrary : : buildDebuggingHelperLibrary ( const QString & qmakePath , const QString & make , const Environment & env )
{
2009-08-07 15:20:05 +02:00
QString errorMessage ;
2009-09-03 19:16:22 +02:00
const QString directory = copyDebuggingHelperLibrary ( qtInstallDataDir ( qmakePath ) , & errorMessage ) ;
2009-05-06 17:56:27 +02:00
if ( directory . isEmpty ( ) )
2009-08-07 15:20:05 +02:00
return errorMessage ;
2009-04-28 12:43:04 +02:00
return buildDebuggingHelperLibrary ( directory , make , qmakePath , QString : : null , env ) ;
}
2009-08-07 15:20:05 +02:00
// Copy helper source files to a target directory, replacing older files.
static bool copyDebuggingHelperFiles ( const QStringList & files ,
const QString & targetDirectory ,
QString * errorMessage )
{
const QString dumperSourcePath = Core : : ICore : : instance ( ) - > resourcePath ( ) + QLatin1String ( " /gdbmacros/ " ) ;
if ( ! QDir ( ) . mkpath ( targetDirectory ) ) {
* errorMessage = QCoreApplication : : translate ( " ProjectExplorer::DebuggingHelperLibrary " , " The target directory %1 could not be created. " ) . arg ( targetDirectory ) ;
return false ;
}
foreach ( const QString & file , files ) {
const QString source = dumperSourcePath + file ;
const QString dest = targetDirectory + file ;
const QFileInfo destInfo ( dest ) ;
if ( destInfo . exists ( ) ) {
if ( destInfo . lastModified ( ) > = QFileInfo ( source ) . lastModified ( ) )
continue ;
if ( ! QFile : : remove ( dest ) ) {
* errorMessage = QCoreApplication : : translate ( " ProjectExplorer::DebuggingHelperLibrary " , " The existing file %1 could not be removed. " ) . arg ( destInfo . absoluteFilePath ( ) ) ;
return false ;
}
}
if ( ! QFile : : copy ( source , dest ) ) {
* errorMessage = QCoreApplication : : translate ( " ProjectExplorer::DebuggingHelperLibrary " , " The file %1 could not be copied to %2. " ) . arg ( source , dest ) ;
return false ;
}
}
return true ;
}
QString DebuggingHelperLibrary : : copyDebuggingHelperLibrary ( const QString & qtInstallData ,
QString * errorMessage )
2009-04-28 12:43:04 +02:00
{
// Locations to try:
// $QTDIR/qtc-debugging-helper
// $APPLICATION-DIR/qtc-debugging-helper/$hash
// $USERDIR/qtc-debugging-helper/$hash
2009-09-03 19:16:22 +02:00
const QStringList directories = DebuggingHelperLibrary : : debuggingHelperLibraryDirectories ( qtInstallData ) ;
2009-04-28 12:43:04 +02:00
QStringList files ;
2009-08-07 15:22:51 +02:00
files < < QLatin1String ( " gdbmacros.cpp " ) < < QLatin1String ( " gdbmacros_p.h " ) < < QLatin1String ( " gdbmacros.h " ) < < QLatin1String ( " gdbmacros.pro " )
2009-08-07 15:20:05 +02:00
< < QLatin1String ( " LICENSE.LGPL " ) < < QLatin1String ( " LGPL_EXCEPTION.TXT " ) ;
// Try to find a writeable directory.
foreach ( const QString & directory , directories )
if ( copyDebuggingHelperFiles ( files , directory , errorMessage ) ) {
errorMessage - > clear ( ) ;
2009-08-07 14:20:27 +02:00
return directory ;
2009-08-07 15:20:05 +02:00
}
* errorMessage = QCoreApplication : : translate ( " ProjectExplorer::DebuggingHelperLibrary " , " The debugger helpers could not be built in any of the directories: \n - %1 \n \n Reason: %2 " )
. arg ( directories . join ( QLatin1String ( " \n - " ) ) , * errorMessage ) ;
return QString ( ) ;
2009-04-28 12:43:04 +02:00
}
QString DebuggingHelperLibrary : : buildDebuggingHelperLibrary ( const QString & directory , const QString & makeCommand , const QString & qmakeCommand , const QString & mkspec , const Environment & env )
{
QString output ;
2009-08-07 15:20:05 +02:00
const QChar newline = QLatin1Char ( ' \n ' ) ;
2009-04-28 12:43:04 +02:00
// Setup process
QProcess proc ;
proc . setEnvironment ( env . toStringList ( ) ) ;
proc . setWorkingDirectory ( directory ) ;
proc . setProcessChannelMode ( QProcess : : MergedChannels ) ;
2009-08-07 15:20:05 +02:00
output + = QCoreApplication : : translate ( " ProjectExplorer::DebuggingHelperLibrary " , " Building debugging helper library in %1 \n " ) . arg ( directory ) ;
output + = newline ;
2009-04-28 12:43:04 +02:00
2009-08-07 15:20:05 +02:00
const QString makeFullPath = env . searchInPath ( makeCommand ) ;
if ( QFileInfo ( directory + QLatin1String ( " /Makefile " ) ) . exists ( ) ) {
2009-07-01 16:33:25 +02:00
if ( ! makeFullPath . isEmpty ( ) ) {
2009-08-07 15:20:05 +02:00
const QString cleanTarget = QLatin1String ( " distclean " ) ;
output + = QCoreApplication : : translate ( " ProjectExplorer::DebuggingHelperLibrary " , " Running %1 %2... \n " ) . arg ( makeFullPath , cleanTarget ) ;
proc . start ( makeFullPath , QStringList ( cleanTarget ) ) ;
2009-07-01 16:33:25 +02:00
proc . waitForFinished ( ) ;
2009-08-07 15:20:05 +02:00
output + = QString : : fromLocal8Bit ( proc . readAll ( ) ) ;
2009-07-01 16:33:25 +02:00
} else {
2009-08-07 15:20:05 +02:00
output + = QCoreApplication : : translate ( " ProjectExplorer::DebuggingHelperLibrary " , " %1 not found in PATH \n " ) . arg ( makeCommand ) ;
2009-07-01 16:33:25 +02:00
return output ;
}
2009-04-28 12:43:04 +02:00
}
2009-08-07 15:20:05 +02:00
output + = newline ;
output + = QCoreApplication : : translate ( " ProjectExplorer::DebuggingHelperLibrary " , " Running %1 ... \n " ) . arg ( qmakeCommand ) ;
2009-04-28 12:43:04 +02:00
2009-08-07 15:20:05 +02:00
QStringList makeArgs ;
makeArgs < < QLatin1String ( " -spec " ) < < ( mkspec . isEmpty ( ) ? QString ( QLatin1String ( " default " ) ) : mkspec ) < < QLatin1String ( " gdbmacros.pro " ) ;
proc . start ( qmakeCommand , makeArgs ) ;
2009-04-28 12:43:04 +02:00
proc . waitForFinished ( ) ;
output + = proc . readAll ( ) ;
2009-08-07 15:20:05 +02:00
output + = newline ; ;
2009-04-28 12:43:04 +02:00
if ( ! makeFullPath . isEmpty ( ) ) {
2009-08-07 15:20:05 +02:00
output + = QCoreApplication : : translate ( " ProjectExplorer::DebuggingHelperLibrary " , " Running %1 ... \n " ) . arg ( makeFullPath ) ;
2009-04-28 12:43:04 +02:00
proc . start ( makeFullPath , QStringList ( ) ) ;
proc . waitForFinished ( ) ;
output + = proc . readAll ( ) ;
} else {
2009-08-07 15:20:05 +02:00
output + = QCoreApplication : : translate ( " ProjectExplorer::DebuggingHelperLibrary " , " %1 not found in PATH \n " ) . arg ( makeCommand ) ;
2009-04-28 12:43:04 +02:00
}
return output ;
}
2009-09-04 09:51:23 +02:00
2009-04-28 12:43:04 +02:00
QString DebuggingHelperLibrary : : qtVersionForQMake ( const QString & qmakePath )
{
2009-09-03 19:16:22 +02:00
QString binary = qmakePath . mid ( qmakePath . lastIndexOf ( ' / ' ) + 1 ) ;
if ( ! possibleQMakeCommands ( ) . contains ( binary ) )
return QString ( ) ;
2009-04-28 12:43:04 +02:00
QProcess qmake ;
2009-08-07 15:20:05 +02:00
qmake . start ( qmakePath , QStringList ( QLatin1String ( " --version " ) ) ) ;
2009-04-28 12:43:04 +02:00
if ( ! qmake . waitForFinished ( ) )
2009-09-03 19:16:22 +02:00
return QString : : null ;
2009-04-28 12:43:04 +02:00
QString output = qmake . readAllStandardOutput ( ) ;
2009-08-07 15:20:05 +02:00
QRegExp regexp ( QLatin1String ( " (QMake version|QMake version:) [ \ \ s ] * ( [ \ \ d . ] * ) " ), Qt::CaseInsensitive) ;
2009-04-28 12:43:04 +02:00
regexp . indexIn ( output ) ;
2009-08-07 15:20:05 +02:00
if ( regexp . cap ( 2 ) . startsWith ( QLatin1String ( " 2. " ) ) ) {
QRegExp regexp2 ( QLatin1String ( " Using Qt version[ \\ s]*([ \\ d \\ .]*) " ), Qt::CaseInsensitive) ;
2009-04-28 12:43:04 +02:00
regexp2 . indexIn ( output ) ;
return regexp2 . cap ( 1 ) ;
}
return QString ( ) ;
}
QStringList DebuggingHelperLibrary : : possibleQMakeCommands ( )
{
// On windows noone has renamed qmake, right?
# ifdef Q_OS_WIN
2009-08-07 15:20:05 +02:00
return QStringList ( QLatin1String ( " qmake.exe " ) ) ;
2009-06-03 20:45:49 +02:00
# else
2009-04-28 12:43:04 +02:00
// On unix some distributions renamed qmake to avoid clashes
QStringList result ;
2009-08-07 15:20:05 +02:00
result < < QLatin1String ( " qmake-qt4 " ) < < QLatin1String ( " qmake4 " ) < < QLatin1String ( " qmake " ) ;
2009-04-28 12:43:04 +02:00
return result ;
2009-06-03 20:45:49 +02:00
# endif
2009-04-28 12:43:04 +02:00
}