diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 3b92eb937c..0185b36ce6 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -1,94 +1,88 @@ find_package(KF5Plasma) set_package_properties(KF5Plasma PROPERTIES PURPOSE "Plasma libraries for enabling the plasma addons" URL "http://www.kde.org" TYPE OPTIONAL) if(KF5Plasma_FOUND) add_subdirectory(plasma) endif() find_package(SharedMimeInfo REQUIRED) option(KDEVELOP_SINGLE_APP "Use QtSingleApplication as KDevelop's base" OFF) set(singleapp_SRCS qtlocalpeer.cpp qtsingleapplication.cpp qtlockedfile.cpp) if(WIN32) set(singleapp_SRCS ${singleapp_SRCS} qtlockedfile_win.cpp) else() set(singleapp_SRCS ${singleapp_SRCS} qtlockedfile_unix.cpp) endif() set(kdevelop_SRCS main.cpp kdevideextension.cpp) if(KDEVELOP_SINGLE_APP) set(kdevelop_SRCS ${kdevelop_SRCS} ${singleapp_SRCS}) endif() qt5_add_resources(kdevelop_SRCS kdevelop.qrc) #TODO: remove CMAKE_CURRENT_SOURCE_DIR prefix when ECM is fixed set(kdevelop_ICONS ${CMAKE_CURRENT_SOURCE_DIR}/icons/16-apps-kdevelop.png ${CMAKE_CURRENT_SOURCE_DIR}/icons/32-apps-kdevelop.png ${CMAKE_CURRENT_SOURCE_DIR}/icons/48-apps-kdevelop.png ${CMAKE_CURRENT_SOURCE_DIR}/icons/64-apps-kdevelop.png ${CMAKE_CURRENT_SOURCE_DIR}/icons/128-apps-kdevelop.png ${CMAKE_CURRENT_SOURCE_DIR}/icons/256-apps-kdevelop.png ) ecm_install_icons(ICONS ${kdevelop_ICONS} DESTINATION ${ICON_INSTALL_DIR}) ecm_add_app_icon(kdevelop_SRCS ICONS ${kdevelop_ICONS}) qt5_add_resources(kdevelop_SRCS kdevelop.qrc) add_executable(kdevelop ${kdevelop_SRCS} ) target_link_libraries(kdevelop KDev::Interfaces KDev::Shell KDev::Util KF5::Declarative KF5::IconThemes KF5::Crash ) IF(APPLE) target_link_libraries(kdevelop "-framework CoreFoundation") ENDIF() install(TARGETS kdevelop ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} ) install(FILES kdevelop! DESTINATION bin PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ) -if(APPLE) - #kde4_add_app_icon(kdevelop_bin_SRCS "${KDE4_ICON_INSTALL_DIR}/oxygen/*/apps/kdevelop.png") -else() - #kde4_add_app_icon(kdevelop_bin_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/../pics/hi*-app-kdevelop.png") -endif() - if (APPLE) # the MacOSX bundle display name property (CFBundleDisplayName) is not currently supported by cmake, # so has to be set for all targets in this cmake file set(MACOSX_BUNDLE_DISPLAY_NAME KDevelop) # We provide our own Info.plist to disable AppNap for KDevelop: set_target_properties(kdevelop PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in) set_target_properties(kdevelop PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER "org.kde.KDevelop") set_target_properties(kdevelop PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "KDevelop") set_target_properties(kdevelop PROPERTIES MACOSX_BUNDLE_DISPLAY_NAME "KDevelop") set_target_properties(kdevelop PROPERTIES MACOSX_BUNDLE_INFO_STRING "The KDevelop Integrated Development Environment") set_target_properties(kdevelop PROPERTIES MACOSX_BUNDLE_LONG_VERSION_STRING "KDevelop ${KDEVELOP_VERSION_MAJOR}.${KDEVELOP_VERSION_MINOR}") set_target_properties(kdevelop PROPERTIES MACOSX_BUNDLE_SHORT_VERSION_STRING "${KDEVELOP_VERSION_MAJOR}.${KDEVELOP_VERSION_MINOR}") set_target_properties(kdevelop PROPERTIES MACOSX_BUNDLE_BUNDLE_VERSION "${KDEVELOP_VERSION_MAJOR}.${KDEVELOP_VERSION_MINOR}") set_target_properties(kdevelop PROPERTIES MACOSX_BUNDLE_ICON_FILE "kdevelop_SRCS.icns") set_target_properties(kdevelop PROPERTIES MACOSX_BUNDLE_COPYRIGHT "KDevelop Team") endif (APPLE) ########### install files ############### install( PROGRAMS org.kde.kdevelop.desktop DESTINATION ${KDE_INSTALL_APPDIR} ) install( PROGRAMS org.kde.kdevelop_ps.desktop DESTINATION ${KDE_INSTALL_APPDIR} ) install( FILES kdevelop.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFY5RCDIR} ) install( FILES kdevelop.xml kdevelopinternal.xml DESTINATION ${KDE_INSTALL_MIMEDIR} ) update_xdg_mimetypes( ${KDE_INSTALL_MIMEDIR} ) diff --git a/debuggers/common/stty.cpp b/debuggers/common/stty.cpp index 70e7aa8320..ab2d616dff 100644 --- a/debuggers/common/stty.cpp +++ b/debuggers/common/stty.cpp @@ -1,348 +1,349 @@ /*************************************************************************** begin : Mon Sep 13 1999 copyright : (C) 1999 by John Birch email : jbb@kdevelop.org This code was originally written by Judin Maxim, from the KDEStudio project. It was then updated with later code from konsole (KDE). It has also been enhanced with an idea from the code in kdbg written by Johannes Sixt ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #ifdef __osf__ #define _XOPEN_SOURCE_EXTENDED #define O_NDELAY O_NONBLOCK #endif #include #include #include #include #include #include #ifdef HAVE_SYS_STROPTS_H #include #define _NEW_TTY_CTRL #endif #include #include #include #include #include #include #include #include #include #include #if defined (_HPUX_SOURCE) #define _TERMIOS_INCLUDED #include #endif #include #include #include #include #include #include #include #include +#include #include "stty.h" #include "debuglog.h" #define PTY_FILENO 3 #define BASE_CHOWN "konsole_grantpty" #include using namespace KDevMI; static int chownpty(int fd, int grant) // param fd: the fd of a master pty. // param grant: 1 to grant, 0 to revoke // returns 1 on success 0 on fail { void(*tmp)(int) = signal(SIGCHLD,SIG_DFL); pid_t pid = fork(); if (pid < 0) { signal(SIGCHLD,tmp); return 0; } if (pid == 0) { /* We pass the master pseudo terminal as file descriptor PTY_FILENO. */ if (fd != PTY_FILENO && dup2(fd, PTY_FILENO) < 0) ::exit(1); QString path = QStandardPaths::findExecutable(BASE_CHOWN); execle(QFile::encodeName(path), BASE_CHOWN, grant?"--grant":"--revoke", (void *)0, NULL); ::exit(1); // should not be reached } if (pid > 0) { int w; // retry: int rc = waitpid (pid, &w, 0); if (rc != pid) ::exit(1); // { // signal from other child, behave like catchChild. // // guess this gives quite some control chaos... // Shell* sh = shells.indexOf(rc); // if (sh) { shells.remove(rc); sh->doneShell(w); } // goto retry; // } signal(SIGCHLD,tmp); return (rc != -1 && WIFEXITED(w) && WEXITSTATUS(w) == 0); } signal(SIGCHLD,tmp); return 0; //dummy. } // ************************************************************************** STTY::STTY(bool ext, const QString &termAppName) : QObject(), out(0), ttySlave(""), m_externalTerminal(0), external_(ext) { if (ext) { findExternalTTY(termAppName); } else { fout = findTTY(); if (fout >= 0) { ttySlave = QString(tty_slave); out = new QSocketNotifier(fout, QSocketNotifier::Read, this); connect( out, &QSocketNotifier::activated, this, &STTY::OutReceived ); } } } // ************************************************************************** STTY::~STTY() { if (out) { ::close(fout); delete out; } } // ************************************************************************** int STTY::findTTY() { int ptyfd = -1; bool needGrantPty = true; // Find a master pty that we can open //////////////////////////////// #ifdef __sgi__ ptyfd = open("/dev/ptmx",O_RDWR); #elif defined(Q_OS_MAC) ptyfd = posix_openpt(O_RDWR); #endif #if defined(__sgi__) || defined(Q_OS_MAC) if (ptyfd == -1) { perror("Can't open a pseudo teletype"); return(-1); } else if (ptyfd >= 0) { strncpy(tty_slave, ptsname(ptyfd), 50); grantpt(ptyfd); unlockpt(ptyfd); needGrantPty = false; } #endif // first we try UNIX PTY's #ifdef TIOCGPTN strcpy(pty_master,"/dev/ptmx"); strcpy(tty_slave,"/dev/pts/"); ptyfd = open(pty_master,O_RDWR); if (ptyfd >= 0) { // got the master pty int ptyno; if (ioctl(ptyfd, TIOCGPTN, &ptyno) == 0) { struct stat sbuf; sprintf(tty_slave,"/dev/pts/%d",ptyno); if (stat(tty_slave,&sbuf) == 0 && S_ISCHR(sbuf.st_mode)) needGrantPty = false; else { close(ptyfd); ptyfd = -1; } } else { close(ptyfd); ptyfd = -1; } } #endif #if defined(_SCO_DS) || defined(__USLC__) /* SCO OSr5 and UnixWare */ if (ptyfd < 0) { for (int idx = 0; idx < 256; idx++) { sprintf(pty_master, "/dev/ptyp%d", idx); sprintf(tty_slave, "/dev/ttyp%d", idx); if (access(tty_slave, F_OK) < 0) { idx = 256; break; } if ((ptyfd = open (pty_master, O_RDWR)) >= 0) { if (access (tty_slave, R_OK|W_OK) == 0) break; close(ptyfd); ptyfd = -1; } } } #endif if (ptyfd < 0) { /// \FIXME Linux, Trouble on other systems? for (const char* s3 = "pqrstuvwxyzabcde"; *s3 != 0; s3++) { for (const char* s4 = "0123456789abcdef"; *s4 != 0; s4++) { sprintf(pty_master,"/dev/pty%c%c",*s3,*s4); sprintf(tty_slave,"/dev/tty%c%c",*s3,*s4); if ((ptyfd = open(pty_master, O_RDWR)) >= 0) { if (geteuid() == 0 || access(tty_slave, R_OK|W_OK) == 0) break; close(ptyfd); ptyfd = -1; } } if (ptyfd >= 0) break; } } if (ptyfd >= 0) { if (needGrantPty && !chownpty(ptyfd, true)) { fprintf(stderr,"kdevelop: chownpty failed for device %s::%s.\n",pty_master,tty_slave); fprintf(stderr," : This means the session can be eavesdroped.\n"); fprintf(stderr," : Make sure konsole_grantpty is installed and setuid root.\n"); } ::fcntl(ptyfd, F_SETFL, O_NDELAY); #ifdef TIOCSPTLCK int flag = 0; ioctl(ptyfd, TIOCSPTLCK, &flag); // unlock pty #endif } if (ptyfd==-1) { m_lastError = i18n("Cannot use the tty* or pty* devices.\n" "Check the settings on /dev/tty* and /dev/pty*\n" "As root you may need to \"chmod ug+rw\" tty* and pty* devices " "and/or add the user to the tty group using " "\"usermod -aG tty username\"."); } return ptyfd; } // ************************************************************************** void STTY::OutReceived(int f) { char buf[1024]; int n; // read until socket is empty. We shouldn't be receiving a continuous // stream of data, so the loop is unlikely to cause problems. while ((n = ::read(f, buf, sizeof(buf)-1)) > 0) { *(buf+n) = 0; // a standard string QByteArray ba(buf); emit OutOutput(ba); } // Note: for some reason, n can be 0 here. // I can understand that non-blocking read returns 0, // but I don't understand how OutRecieved can be even // called when there's no input. if (n == 0 /* eof */ || (n == -1 && errno != EAGAIN)) { // Found eof or error. Disable socket notifier, otherwise Qt // will repeatedly call this method, eating CPU // cycles. out->setEnabled(false); } } void STTY::readRemaining() { if (!external_) OutReceived(fout); } bool STTY::findExternalTTY(const QString& termApp) { QString appName(termApp.isEmpty() ? QString("xterm") : termApp); if (QStandardPaths::findExecutable(appName).isEmpty()) { m_lastError = i18n("%1 is incorrect terminal name", termApp); return false; } QTemporaryFile file; if (!file.open()) { m_lastError = i18n("Can't create a temporary file"); return false; } m_externalTerminal.reset(new QProcess(this)); KDevelop::restoreSystemEnvironment(m_externalTerminal.data()); if (appName == "konsole") { m_externalTerminal->start(appName, QStringList() << "-e" << "sh" << "-c" << "tty>" + file.fileName() + ";exec<&-;exec>&-;while :;do sleep 3600;done"); } else if (appName == "xfce4-terminal") { m_externalTerminal->start(appName, QStringList() << "-e" << " sh -c \"tty>" + file.fileName() + ";\"\"<&\\-\"\">&\\-;\"\"while :;\"\"do sleep 3600;\"\"done\""); } else { m_externalTerminal->start(appName, QStringList() << "-e" << "sh -c \"tty>" + file.fileName() + ";exec<&-;exec>&-;while :;do sleep 3600;done\""); } if (!m_externalTerminal->waitForStarted(500)) { m_lastError = "Can't run terminal: " + appName; m_externalTerminal->terminate(); return false; } for (int i = 0; i < 800; i++) { if (!file.bytesAvailable()) { if (m_externalTerminal->state() == QProcess::NotRunning && m_externalTerminal->exitCode()) { break; } QCoreApplication::processEvents(QEventLoop::AllEvents, 100); usleep(8000); } else { qCDebug(DEBUGGERGDB) << "Received terminal output(tty)"; break; } } usleep(1000); ttySlave = file.readAll().trimmed(); file.close(); if (ttySlave.isEmpty()) { m_lastError = i18n("Can't receive %1 tty/pty. Check that %1 is actually a terminal and that it accepts these arguments: -e sh -c \"tty> %2 ;exec<&-;exec>&-;while :;do sleep 3600;done\"", appName, file.fileName()); } return true; } // ************************************************************************** diff --git a/debuggers/gdb/debugsession.cpp b/debuggers/gdb/debugsession.cpp index 99eec51124..bba068b9b7 100644 --- a/debuggers/gdb/debugsession.cpp +++ b/debuggers/gdb/debugsession.cpp @@ -1,273 +1,278 @@ /* * GDB Debugger Support * * Copyright 1999-2001 John Birch * Copyright 2001 by Bernd Gehrmann * Copyright 2006 Vladimir Prus * Copyright 2007 Hamish Rodda * Copyright 2009 Niko Sams * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "debugsession.h" #include "debuglog.h" #include "gdb.h" #include "gdbbreakpointcontroller.h" #include "gdbframestackmodel.h" #include "mi/micommand.h" #include "stty.h" #include "variablecontroller.h" +#include +#include +#include +#include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KDevMI::GDB; using namespace KDevMI::MI; using namespace KDevelop; DebugSession::DebugSession() : MIDebugSession() , m_breakpointController(nullptr) , m_variableController(nullptr) , m_frameStackModel(nullptr) { m_breakpointController = new BreakpointController(this); m_variableController = new VariableController(this); m_frameStackModel = new GdbFrameStackModel(this); } DebugSession::~DebugSession() { } BreakpointController *DebugSession::breakpointController() const { return m_breakpointController; } VariableController *DebugSession::variableController() const { return m_variableController; } GdbFrameStackModel *DebugSession::frameStackModel() const { return m_frameStackModel; } GdbDebugger *DebugSession::createDebugger() const { return new GdbDebugger; } void DebugSession::initializeDebugger() { //queueCmd(new GDBCommand(GDBMI::EnableTimings, "yes")); queueCmd(new CliCommand(MI::GdbShow, "version", this, &DebugSession::handleVersion)); // This makes gdb pump a variable out on one line. queueCmd(new MICommand(MI::GdbSet, "width 0")); queueCmd(new MICommand(MI::GdbSet, "height 0")); queueCmd(new MICommand(MI::SignalHandle, "SIG32 pass nostop noprint")); queueCmd(new MICommand(MI::SignalHandle, "SIG41 pass nostop noprint")); queueCmd(new MICommand(MI::SignalHandle, "SIG42 pass nostop noprint")); queueCmd(new MICommand(MI::SignalHandle, "SIG43 pass nostop noprint")); queueCmd(new MICommand(MI::EnablePrettyPrinting)); queueCmd(new MICommand(MI::GdbSet, "charset UTF-8")); queueCmd(new MICommand(MI::GdbSet, "print sevenbit-strings off")); QString fileName = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kdevgdb/printers/gdbinit"); if (!fileName.isEmpty()) { QFileInfo fileInfo(fileName); QString quotedPrintersPath = fileInfo.dir().path() .replace('\\', "\\\\") .replace('"', "\\\""); queueCmd(new MICommand(MI::NonMI, QString("python sys.path.insert(0, \"%0\")").arg(quotedPrintersPath))); queueCmd(new MICommand(MI::NonMI, "source " + fileName)); } qCDebug(DEBUGGERGDB) << "Initialized GDB"; } void DebugSession::configure(ILaunchConfiguration *cfg) { // Read Configuration values KConfigGroup grp = cfg->config(); bool breakOnStart = grp.readEntry(KDevMI::breakOnStartEntry, false); bool displayStaticMembers = grp.readEntry(KDevMI::staticMembersEntry, false); bool asmDemangle = grp.readEntry(KDevMI::demangleNamesEntry, true); if (breakOnStart) { BreakpointModel* m = ICore::self()->debugController()->breakpointModel(); bool found = false; foreach (Breakpoint *b, m->breakpoints()) { if (b->location() == "main") { found = true; break; } } if (!found) { m->addCodeBreakpoint("main"); } } // Needed so that breakpoint widget has a chance to insert breakpoints. // FIXME: a bit hacky, as we're really not ready for new commands. setDebuggerStateOn(s_dbgBusy); raiseEvent(debugger_ready); if (displayStaticMembers) { queueCmd(new MICommand(MI::GdbSet, "print static-members on")); } else { queueCmd(new MICommand(MI::GdbSet, "print static-members off")); } if (asmDemangle) { queueCmd(new MICommand(MI::GdbSet, "print asm-demangle on")); } else { queueCmd(new MICommand(MI::GdbSet, "print asm-demangle off")); } qCDebug(DEBUGGERGDB) << "Per inferior configuration done"; } bool DebugSession::execInferior(ILaunchConfiguration *cfg, const QString &executable) { qCDebug(DEBUGGERGDB) << "Executing inferior"; // debugger specific config configure(cfg); KConfigGroup grp = cfg->config(); QUrl configGdbScript = grp.readEntry(KDevMI::remoteGdbConfigEntry, QUrl()); QUrl runShellScript = grp.readEntry(KDevMI::remoteGdbShellEntry, QUrl()); QUrl runGdbScript = grp.readEntry(KDevMI::remoteGdbRunEntry, QUrl()); // handle remote debug if (configGdbScript.isValid()) { queueCmd(new MICommand(MI::NonMI, "source " + KShell::quoteArg(configGdbScript.toLocalFile()))); } // FIXME: have a check box option that controls remote debugging if (runShellScript.isValid()) { // Special for remote debug, the remote inferior is started by this shell script QByteArray tty(m_tty->getSlave().toLatin1()); QByteArray options = QByteArray(">") + tty + QByteArray(" 2>&1 <") + tty; QProcess *proc = new QProcess; KDevelop::restoreSystemEnvironment(proc); QStringList arguments; arguments << "-c" << KShell::quoteArg(runShellScript.toLocalFile()) + ' ' + KShell::quoteArg(executable) + QString::fromLatin1(options); qCDebug(DEBUGGERGDB) << "starting sh" << arguments; proc->start("sh", arguments); //PORTING TODO QProcess::DontCare); } if (runGdbScript.isValid()) { // Special for remote debug, gdb script at run is requested, to connect to remote inferior // Race notice: wait for the remote gdbserver/executable // - but that might be an issue for this script to handle... // Note: script could contain "run" or "continue" // Future: the shell script should be able to pass info (like pid) // to the gdb script... queueCmd(new SentinelCommand([this, runGdbScript]() { breakpointController()->initSendBreakpoints(); breakpointController()->setDeleteDuplicateBreakpoints(true); qCDebug(DEBUGGERGDB) << "Running gdb script " << KShell::quoteArg(runGdbScript.toLocalFile()); queueCmd(new MICommand(MI::NonMI, "source " + KShell::quoteArg(runGdbScript.toLocalFile()), [this](const MI::ResultRecord&) { breakpointController()->setDeleteDuplicateBreakpoints(false); }, CmdMaybeStartsRunning)); raiseEvent(connected_to_program); }, CmdMaybeStartsRunning)); } else { // normal local debugging queueCmd(new MICommand(MI::FileExecAndSymbols, KShell::quoteArg(executable), this, &DebugSession::handleFileExecAndSymbols, CmdHandlesError)); raiseEvent(connected_to_program); queueCmd(new SentinelCommand([this]() { breakpointController()->initSendBreakpoints(); queueCmd(new MICommand(MI::ExecRun, QString(), CmdMaybeStartsRunning)); }, CmdMaybeStartsRunning)); } return true; } void DebugSession::handleVersion(const QStringList& s) { qCDebug(DEBUGGERGDB) << s.first(); // minimal version is 7.0,0 QRegExp rx("([7-9]+)\\.([0-9]+)(\\.([0-9]+))?"); int idx = rx.indexIn(s.first()); if (idx == -1) { if (!qobject_cast(qApp)) { //for unittest qFatal("You need a graphical application."); } KMessageBox::error( qApp->activeWindow(), i18n("You need gdb 7.0.0 or higher.
" "You are using: %1", s.first()), i18n("gdb error")); stopDebugger(); } } void DebugSession::handleFileExecAndSymbols(const MI::ResultRecord& r) { if (r.reason == "error") { KMessageBox::error( qApp->activeWindow(), i18n("Could not start debugger:
")+ r["msg"].literal(), i18n("Startup error")); stopDebugger(); } } diff --git a/projectmanagers/qmake/qmakejob.cpp b/projectmanagers/qmake/qmakejob.cpp index b4f6cec247..dfaf753de0 100644 --- a/projectmanagers/qmake/qmakejob.cpp +++ b/projectmanagers/qmake/qmakejob.cpp @@ -1,163 +1,163 @@ /*************************************************************************** * This file is part of KDevelop * * Copyright 2010 Milian Wolff * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "qmakejob.h" #include #include #include #include #include #include #include #include #include #include #include "debug.h" using namespace KDevelop; QMakeJob::QMakeJob(QString srcDir, QString buildDir, QObject* parent) : OutputJob(parent) , m_srcDir(std::move(srcDir)) , m_buildDir(std::move(buildDir)) , m_qmakePath("qmake") , m_buildType(0) , m_process(nullptr) , m_model(nullptr) { setCapabilities(Killable); setStandardToolView(IOutputView::RunView); setBehaviours(IOutputView::AllowUserClose | IOutputView::AutoScroll); setObjectName(i18n("Run QMake in %1", m_buildDir)); } QMakeJob::~QMakeJob() { } void QMakeJob::setQMakePath(const QString& path) { m_qmakePath = path; } void QMakeJob::setInstallPrefix(const QString& prefix) { m_installPrefix = prefix; } void QMakeJob::setBuildType(int comboboxSelectedIndex) { m_buildType = comboboxSelectedIndex; } void QMakeJob::setExtraArguments(const QString& args) { m_extraArguments = args; } void QMakeJob::start() { static const char* BUILD_TYPES[] = { "debug", "build", "(don't specify)" }; m_model = new OutputModel; setModel(m_model); startOutput(); QStringList args; if (m_buildType < 2) args << QString("CONFIG+=") + BUILD_TYPES[m_buildType]; if (!m_installPrefix.isEmpty()) args << "target.path=" + m_installPrefix; if (!m_extraArguments.isEmpty()) { KShell::Errors err; QStringList tmp = KShell::splitArgs(m_extraArguments, KShell::TildeExpand | KShell::AbortOnMeta, &err); if (err == KShell::NoError) { args += tmp; } else { qCWarning(KDEV_QMAKE) << "Ignoring qmake Extra arguments"; if (err == KShell::BadQuoting) { qCWarning(KDEV_QMAKE) << "QMake arguments badly quoted:" << m_extraArguments; } else { qCWarning(KDEV_QMAKE) << "QMake arguments had meta character:" << m_extraArguments; } } } args << "-r" << m_srcDir; m_model->appendLine(m_buildDir + ": " + args.join(" ")); QDir build(m_buildDir); if (!build.exists()) { build.mkpath(build.absolutePath()); } m_process = new QProcess(this); - KDevPlatform::restoreSystemEnvironment(m_process); + KDevelop::restoreSystemEnvironment(m_process); m_process->setWorkingDirectory(m_buildDir); m_process->setProgram(m_qmakePath); m_process->setArguments(args); m_process->setProcessChannelMode(QProcess::MergedChannels); auto lineMaker = new KDevelop::ProcessLineMaker(m_process, this); connect(lineMaker, SIGNAL(receivedStdoutLines(QStringList)), m_model, SLOT(appendLines(QStringList))); connect(lineMaker, SIGNAL(receivedStderrLines(QStringList)), m_model, SLOT(appendLines(QStringList))); connect(m_process, SIGNAL(error(QProcess::ProcessError)), SLOT(processError(QProcess::ProcessError))); connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(processFinished(int, QProcess::ExitStatus))); m_process->start(); } bool QMakeJob::doKill() { if (!m_process) { return true; } m_process->kill(); return m_process->state() == m_process->NotRunning; } QString QMakeJob::errorString() const { return m_process->errorString(); } void QMakeJob::processError(QProcess::ProcessError error) { m_model->appendLine(errorString()); setError(error); emitResult(); } void QMakeJob::processFinished(int exitCode, QProcess::ExitStatus status) { if (status == QProcess::NormalExit) { m_model->appendLine(i18n("*** Exited with return code: %1 ***", exitCode)); } else if (error() == KJob::KilledJobError) { m_model->appendLine(i18n("*** Process aborted ***")); } else { m_model->appendLine(i18n("*** Crashed with return code: %1 ***", exitCode)); } emitResult(); }