/*************************************************************************** * Copyright (C) 2001-2002 by Bernd Gehrmann * * bernd@kdevelop.org * * * * Copyright (C) 2002 by Victor Roeder * * victor_roeder@gmx.de * * * * 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. * * * ***************************************************************************/ #include #include "autoprojectpart.h" #include "autolistviewitems.h" #include "configureoptionswidget.h" #include "addtranslationdlg.h" #include "addicondlg.h" #include "autoprojectwidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define CONFIGURE_OPTIONS 1 #define RUN_OPTIONS 2 #define MAKE_OPTIONS 3 static const KDevPluginInfo data("kdevautoproject"); K_EXPORT_COMPONENT_FACTORY( libkdevautoproject, AutoProjectFactory( data ) ) AutoProjectPart::AutoProjectPart(QObject *parent, const char *name, const QStringList &args) : KDevBuildTool(&data, parent, name ? name : "AutoProjectPart") , m_lastCompilationFailed(false) { setInstance(AutoProjectFactory::instance()); setXMLFile("kdevautoproject.rc"); m_executeAfterBuild = false; m_isKDE = (args[0] == "kde"); m_needMakefileCvs = false; m_widget = new AutoProjectWidget(this, m_isKDE); m_widget->setIcon(SmallIcon( info()->icon() )); m_widget->setCaption(i18n("Automake Manager")); QWhatsThis::add(m_widget, i18n("Automake manager

" "The project tree consists of two parts. The 'overview' " "in the upper half shows the subprojects, each one having a " "Makefile.am. The 'details' view in the lower half shows the " "targets and files for the subproject selected in the overview.")); mainWindow()->embedSelectViewRight(m_widget, i18n("Automake Manager"), i18n("Automake manager")); KAction *action; action = new KAction( i18n("Add Translation..."), 0, this, SLOT(slotAddTranslation()), actionCollection(), "project_addtranslation" ); action->setToolTip(i18n("Add translation")); action->setWhatsThis(i18n("Add translation

Creates .po file for the selected language.")); action->setGroup("autotools"); if (!m_isKDE) action->setEnabled(false); action = new KAction( i18n("&Build Project"), "make_kdevelop", Key_F8, this, SLOT(slotBuild()), actionCollection(), "build_build" ); action->setToolTip(i18n("Build project")); action->setWhatsThis(i18n("Build project

Runs make from the project directory.
" "Environment variables and make arguments can be specified " "in the project settings dialog, Make Options tab.")); action->setGroup("autotools"); action = new KAction( i18n("Build &Active Target"), "make_kdevelop", Key_F7, this, SLOT(slotBuildActiveTarget()), actionCollection(), "build_buildactivetarget" ); action->setToolTip(i18n("Build active target")); action->setWhatsThis(i18n("Build active target

Constructs a series of make commands to build an active target. " "Also builds dependent targets.
" "Environment variables and make arguments can be specified " "in the project settings dialog, Make Options tab.")); action->setGroup("autotools"); action = new KAction( i18n("Compile &File"), "make_kdevelop", this, SLOT(slotCompileFile()), actionCollection(), "build_compilefile" ); action->setToolTip(i18n("Compile file")); action->setWhatsThis(i18n("Compile file

Runs make filename.o command from the directory where 'filename' is the name of currently opened file.
" "Environment variables and make arguments can be specified " "in the project settings dialog, Make Options tab.")); action->setGroup("autotools"); action = new KAction( i18n("Run Configure"), 0, this, SLOT(slotConfigure()), actionCollection(), "build_configure" ); action->setToolTip(i18n("Run configure")); action->setWhatsThis(i18n("Run configure

Executes configure with flags, arguments " "and environment variables specified in the project settings dialog, " "Configure Options tab.")); action->setGroup("autotools"); action = new KAction( i18n("Run automake && friends"), 0, this, SLOT(slotMakefilecvs()), actionCollection(), "build_makefilecvs" ); action->setToolTip(i18n("Run automake && friends")); action->setWhatsThis(i18n("Run automake && friends

Executes
make -f Makefile.cvs
./configure
commands from the project directory.")); action->setGroup("autotools"); action = new KAction( i18n("Install"), 0, this, SLOT(slotInstall()), actionCollection(), "build_install" ); action->setToolTip(i18n("Install")); action->setWhatsThis(i18n("Install

Runs make install command from the project directory.
" "Environment variables and make arguments can be specified " "in the project settings dialog, Make Options tab.")); action->setGroup("autotools"); action = new KAction( i18n("Install (as root user)"), 0, this, SLOT(slotInstallWithKdesu()), actionCollection(), "build_install_kdesu" ); action->setToolTip(i18n("Install as root user")); action->setWhatsThis(i18n("Install

Runs make install command from the project directory with root privileges.
" "It is executed via kdesu command.
" "Environment variables and make arguments can be specified " "in the project settings dialog, Make Options tab.")); action->setGroup("autotools"); action = new KAction( i18n("&Clean Project"), 0, this, SLOT(slotClean()), actionCollection(), "build_clean" ); action->setToolTip(i18n("Clean project")); action->setWhatsThis(i18n("Clean project

Runs make clean command from the project directory.
" "Environment variables and make arguments can be specified " "in the project settings dialog, Make Options tab.")); action->setGroup("autotools"); action = new KAction( i18n("&Distclean"), 0, this, SLOT(slotDistClean()), actionCollection(), "build_distclean" ); action->setToolTip(i18n("Distclean")); action->setWhatsThis(i18n("Distclean

Runs make distclean command from the project directory.
" "Environment variables and make arguments can be specified " "in the project settings dialog, Make Options tab.")); action->setGroup("autotools"); action = new KAction( i18n("Make Messages && Merge"), 0, this, SLOT(slotMakeMessages()), actionCollection(), "build_messages" ); action->setToolTip(i18n("Make messages && merge")); action->setWhatsThis(i18n("Make messages && merge

Runs make package-messages command from the project directory.
" "Environment variables and make arguments can be specified " "in the project settings dialog, Make Options tab.")); action->setGroup("autotools"); if (!m_isKDE) action->setEnabled(false); buildConfigAction = new KSelectAction( i18n("Build Configuration"), 0, actionCollection(), "project_configuration" ); buildConfigAction->setToolTip(i18n("Build configuration menu")); buildConfigAction->setWhatsThis(i18n("Build configuration menu

Allows to switch between project build configurations.
" "Build configuration is a set of build and top source directory settings, " "configure flags and arguments, compiler flags, etc.
" "Modify build configurations in project settings dialog, Configure Options tab.")); buildConfigAction->setGroup("autotools"); QDomDocument &dom = *projectDom(); if (!DomUtil::readBoolEntry(dom, "/kdevautoproject/run/disable_default")) { //ok we handle the execute in this kpart action = new KAction( i18n("Execute Program"), "exec", SHIFT+Key_F9, this, SLOT(slotExecute()), actionCollection(), "build_execute" ); action->setToolTip(i18n("Execute program")); action->setWhatsThis(i18n("Execute program

Executes the currently active target or the main program specified in project settings, Run Options tab.")); action->setGroup("autotools"); } connect( buildConfigAction, SIGNAL(activated(const QString&)), this, SLOT(slotBuildConfigChanged(const QString&)) ); connect( buildConfigAction->popupMenu(), SIGNAL(aboutToShow()), this, SLOT(slotBuildConfigAboutToShow()) ); // connect( core(), SIGNAL(projectConfigWidget(KDialogBase*)), this, SLOT(projectConfigWidget(KDialogBase*)) ); _configProxy = new ConfigWidgetProxy( core() ); _configProxy->createProjectConfigPage( i18n("Configure Options"), CONFIGURE_OPTIONS, info()->icon() ); _configProxy->createProjectConfigPage( i18n("Run Options"), RUN_OPTIONS, info()->icon() ); _configProxy->createProjectConfigPage( i18n("Make Options"), MAKE_OPTIONS, info()->icon() ); connect( _configProxy, SIGNAL(insertConfigWidget(const KDialogBase*, QWidget*, unsigned int )), this, SLOT(insertConfigWidget(const KDialogBase*, QWidget*, unsigned int )) ); connect( makeFrontend(), SIGNAL(commandFinished(const QString&)), this, SLOT(slotCommandFinished(const QString&)) ); connect( makeFrontend(), SIGNAL(commandFailed(const QString&)), this, SLOT(slotCommandFailed(const QString&)) ); setWantautotools(); } AutoProjectPart::~AutoProjectPart() { if (m_widget) { mainWindow()->removeView(m_widget); } delete m_widget; delete _configProxy; } void AutoProjectPart::insertConfigWidget( const KDialogBase* dlg, QWidget * page, unsigned int pagenumber ) { switch ( pagenumber ) { case CONFIGURE_OPTIONS: { ConfigureOptionsWidget *w2 = new ConfigureOptionsWidget(this, page ); connect( dlg, SIGNAL(okClicked()), w2, SLOT(accept()) ); } break; case RUN_OPTIONS: { QDomDocument &dom = *projectDom(); if (!DomUtil::readBoolEntry(dom, "/kdevautoproject/run/disable_default")) { //ok we handle the execute in this kpart RunOptionsWidget *w3 = new RunOptionsWidget(*projectDom(), "/kdevautoproject", buildDirectory(), page ); connect( dlg, SIGNAL(okClicked()), w3, SLOT(accept()) ); } } break; case MAKE_OPTIONS: { MakeOptionsWidget *w4 = new MakeOptionsWidget(*projectDom(), "/kdevautoproject", page ); connect( dlg, SIGNAL(okClicked()), w4, SLOT(accept()) ); } break; } } void AutoProjectPart::openProject(const QString &dirName, const QString &projectName) { m_projectName = projectName; m_projectPath =dirName; m_widget->openProject(dirName); QDomDocument &dom = *projectDom(); QString activeTarget = DomUtil::readEntry(dom, "/kdevautoproject/general/activetarget"); kdDebug(9020) << k_funcinfo << "activeTarget " << activeTarget << endl; if (!activeTarget.isEmpty()) m_widget->setActiveTarget(activeTarget); else { KMessageBox::information( m_widget, i18n("No active target specified, running the application will\n" "not work until you make a target active in the Automake Manager\n" "on the right side or use the Main Program options under\n" "Project -> Project Options -> Run Options"), i18n("No active target specified"), "kdevelop_open_project_no_active_target"); } KDevProject::openProject( dirName, projectName ); } void AutoProjectPart::closeProject() { m_widget->closeProject(); } QString AutoProjectPart::projectDirectory() const { return m_projectPath; } QString AutoProjectPart::projectName() const { return m_projectName; } /** Retuns a PairList with the run environment variables */ DomUtil::PairList AutoProjectPart::runEnvironmentVars() const { return DomUtil::readPairListEntry(*projectDom(), "/kdevautoproject/run/envvars", "envvar", "name", "value"); } /** Retuns the currently selected run directory * If no main Program was selected in the Run Options dialog * use the currently active target instead to calculate it. * The returned string can be: * if /kdevautoproject/run/directoryradio == executable * The directory where the executable is * if /kdevautoproject/run/directoryradio == build * The directory where the executable is relative to build directory * if /kdevautoproject/run/directoryradio == custom * The custom directory absolute path */ QString AutoProjectPart::runDirectory() const { QDomDocument &dom = *projectDom(); QString cwd; if( DomUtil::readBoolEntry(dom, "/kdevautoproject/run/useglobalprogram", false) || !m_widget->activeTarget() ) { cwd = defaultRunDirectory("kdevautoproject"); }else { cwd = DomUtil::readEntry( dom, "/kdevautoproject/run/cwd/"+m_widget->activeTarget()->name ); } if( cwd.isEmpty() ) cwd = buildDirectory() +"/"+ URLUtil::getRelativePath( topsourceDirectory(), projectDirectory() ) +"/"+m_widget->activeDirectory(); return cwd; } /** Retuns the currently selected main program * If no main Program was selected in the Run Options dialog * use the currently active target instead. * The returned string can be: * if /kdevautoproject/run/directoryradio == executable * The executable name * if /kdevautoproject/run/directoryradio == build * The path to executable relative to build directory * if /kdevautoproject/run/directoryradio == custom or relative == false * The absolute path to executable */ QString AutoProjectPart::mainProgram() const { QDomDocument * dom = projectDom(); if ( !dom ) return QString(); if( DomUtil::readBoolEntry(*dom, "/kdevautoproject/run/useglobalprogram", false) ) { QString DomMainProgram = DomUtil::readEntry(*dom, "/kdevautoproject/run/mainprogram"); if ( DomMainProgram.isEmpty() ) return QString(); if ( DomMainProgram.startsWith("/") ) // assume absolute path { return DomMainProgram; } else // assume builddir relative path { QString relprojectpath = URLUtil::getRelativePath( topsourceDirectory(), projectDirectory() ); if( !relprojectpath.isEmpty() ) relprojectpath = "/" + relprojectpath; return buildDirectory() + relprojectpath + "/" + DomMainProgram; } } else // If no Main Program was specified, return the active target { TargetItem* titem = m_widget->activeTarget(); if ( !titem ) { KMessageBox::error( m_widget, i18n("There is no active target.\n" "Unable to determine the main program."), i18n("No active target found") ); kdDebug ( 9020 ) << k_funcinfo << "Error! : There's no active target! -> Unable to determine the main program in AutoProjectPart::mainProgram()" << endl; return QString::null; } if ( titem->primary != "PROGRAMS" ) { KMessageBox::error( m_widget, i18n("Active target \"%1\" is not binary ( %2 ).\n" "Unable to determine the main program. If you want this\n" "to be the active target, set a main program under\n" "Project -> Project Options -> Run Options").arg(titem->name).arg(titem->primary), i18n("Active target is not a library") ); kdDebug ( 9020 ) << k_funcinfo << "Error! : Active target isn't binary (" << titem->primary << ") ! -> Unable to determine the main program in AutoProjectPart::mainProgram()" << endl; return QString::null; } QString relprojectpath = URLUtil::getRelativePath( topsourceDirectory(), projectDirectory() ); if( !relprojectpath.isEmpty() ) relprojectpath = "/" + relprojectpath; return buildDirectory() + relprojectpath + "/" + activeDirectory() + "/" + titem->name; } } /** Retuns a QString with the debug command line arguments */ QString AutoProjectPart::debugArguments() const { QDomDocument &dom = *projectDom(); if( DomUtil::readBoolEntry(dom, "/kdevautoproject/run/useglobalprogram", false) || !m_widget->activeTarget() ) { return DomUtil::readEntry(dom, "/kdevautoproject/run/globaldebugarguments"); }else { return DomUtil::readEntry(dom, "/kdevautoproject/run/debugarguments/" + m_widget->activeTarget()->name); } } /** Retuns a QString with the run command line arguments */ QString AutoProjectPart::runArguments() const { QDomDocument &dom = *projectDom(); if( DomUtil::readBoolEntry(dom, "/kdevautoproject/run/useglobalprogram", false) || !m_widget->activeTarget() ) { return DomUtil::readEntry(dom, "/kdevautoproject/run/programargs"); }else { return DomUtil::readEntry(dom, "/kdevautoproject/run/runarguments/" + m_widget->activeTarget()->name); } } QString AutoProjectPart::activeDirectory() const { return m_widget->activeDirectory(); } QStringList AutoProjectPart::allFiles() const { return m_widget->allFiles(); } void AutoProjectPart::setWantautotools() { QDomDocument &dom = *projectDom(); QDomElement el = DomUtil::elementByPath(dom, "/kdevautoproject/make"); if ( el.namedItem("envvars").isNull() ) { DomUtil::PairList list; list << DomUtil::Pair("WANT_AUTOCONF_2_5", "1"); list << DomUtil::Pair("WANT_AUTOMAKE_1_6", "1"); DomUtil::writePairListEntry(dom, "/kdevautoproject/make/envvars", "envvar", "name", "value", list); } } QString AutoProjectPart::makeEnvironment() const { // Get the make environment variables pairs into the environstr string // in the form of: "ENV_VARIABLE=ENV_VALUE" // Note that we quote the variable value due to the possibility of // embedded spaces DomUtil::PairList envvars = DomUtil::readPairListEntry(*projectDom(), "/kdevautoproject/make/envvars", "envvar", "name", "value"); QString environstr; DomUtil::PairList::ConstIterator it; for (it = envvars.begin(); it != envvars.end(); ++it) { environstr += (*it).first; environstr += "="; environstr += EnvVarTools::quote((*it).second); environstr += " "; } KConfigGroup grp( kapp->config(), "MakeOutputView" ); if( grp.readBoolEntry( "ForceCLocale", true ) ) environstr += "LC_MESSAGES="+EnvVarTools::quote("C")+" "+"LC_CTYPE="+EnvVarTools::quote("C")+" "; return environstr; } void AutoProjectPart::addFile(const QString &fileName) { QStringList fileList; fileList.append ( fileName ); this->addFiles ( fileList ); } void AutoProjectPart::addFiles ( const QStringList& fileList ) { QString directory, name; QStringList::ConstIterator it; bool messageBoxShown = false; for ( it = fileList.begin(); it != fileList.end(); ++it ) { int pos = ( *it ).findRev('/'); if (pos != -1) { directory = ( *it ).left(pos); name = ( *it ).mid(pos+1); } else { directory = ""; name = ( *it ); } if (directory != m_widget->activeDirectory() || directory.isEmpty()) { if ( !messageBoxShown ) { KMessageBox::information(m_widget, i18n("The directory you selected is not the active directory.\n" "You should 'activate' the target you're currently working on in Automake Manager.\n" "Just right-click a target and choose 'Make Target Active'."), i18n ( "No Active Target Found" ), "No automake manager active target warning" ); messageBoxShown = true; } } } m_widget->addFiles(fileList); } void AutoProjectPart::removeFile(const QString &fileName) { QStringList fileList; fileList.append ( fileName ); this->removeFiles ( fileList ); } void AutoProjectPart::removeFiles ( const QStringList& fileList ) { /// \FIXME m_widget->removeFiles does nothing! m_widget->removeFiles ( fileList ); emit removedFilesFromProject ( fileList ); } QStringList AutoProjectPart::allBuildConfigs() const { QDomDocument &dom = *projectDom(); QStringList allConfigs; allConfigs.append("default"); QDomNode node = dom.documentElement().namedItem("kdevautoproject").namedItem("configurations"); QDomElement childEl = node.firstChild().toElement(); while (!childEl.isNull()) { QString config = childEl.tagName(); kdDebug(9020) << k_funcinfo << "Found config " << config << endl; if (config != "default") allConfigs.append(config); childEl = childEl.nextSibling().toElement(); } return allConfigs; } QString AutoProjectPart::currentBuildConfig() const { QDomDocument &dom = *projectDom(); QString config = DomUtil::readEntry(dom, "/kdevautoproject/general/useconfiguration"); if (config.isEmpty() || !allBuildConfigs().contains(config)) config = "default"; return config; } QString AutoProjectPart::buildDirectory() const { QString prefix = "/kdevautoproject/configurations/" + currentBuildConfig() + "/"; QString builddir = DomUtil::readEntry(*projectDom(), prefix + "builddir"); if (builddir.isEmpty()) return topsourceDirectory(); else if (builddir.startsWith("/")) return builddir; else return projectDirectory() + "/" + builddir; } QString AutoProjectPart::topsourceDirectory() const { QString prefix = "/kdevautoproject/configurations/" + currentBuildConfig() + "/"; QString topsourcedir = DomUtil::readEntry(*projectDom(), prefix + "topsourcedir"); if (topsourcedir.isEmpty()) return projectDirectory(); else if (topsourcedir.startsWith("/")) return topsourcedir; else return projectDirectory() + "/" + topsourcedir; } QString AutoProjectPart::constructMakeCommandLine(const QString &dir, const QString &target) const { QString preCommand; QFileInfo fi1(); kdDebug(9020) << k_funcinfo << "Looking for Makefile in " << dir << endl; if ( !QFile::exists(dir + "/GNUmakefile") && !QFile::exists(dir + "/makefile") && ! QFile::exists(dir + "/Makefile") ) { if (!QFile::exists(buildDirectory() + "/configure")) { int r = KMessageBox::questionYesNo(m_widget, i18n("%1\nThere is no Makefile in this directory\n" "and no configure script for this project.\n" "Run automake & friends and configure first?").arg(buildDirectory()), QString::null, i18n("Run Them"), i18n("Do Not Run")); if (r == KMessageBox::No) return QString::null; preCommand = makefileCvsCommand(); if (preCommand.isNull()) return QString::null; preCommand += " && "; preCommand += configureCommand() + " && "; } else { int r = KMessageBox::questionYesNo(m_widget, i18n("%1\nThere is no Makefile in this directory. Run 'configure' first?").arg(dir), QString::null, i18n("Run configure"), i18n("Do Not Run")); if (r == KMessageBox::No) return QString::null; preCommand = configureCommand() + " && "; } } QDomDocument &dom = *projectDom(); QString cmdline = DomUtil::readEntry(dom, "/kdevautoproject/make/makebin"); int prio = DomUtil::readIntEntry(dom, "/kdevautoproject/make/prio"); QString nice; kdDebug(9020) << k_funcinfo << "nice = " << prio<< endl; if (prio != 0) { nice = QString("nice -n%1 ").arg(prio); } if (cmdline.isEmpty()) cmdline = MAKE_COMMAND; if (!DomUtil::readBoolEntry(dom, "/kdevautoproject/make/abortonerror")) cmdline += " -k"; bool runmultiple = DomUtil::readBoolEntry(dom, "/kdevautoproject/make/runmultiplejobs"); int jobs = DomUtil::readIntEntry(dom, "/kdevautoproject/make/numberofjobs"); if (runmultiple && jobs != 0) { cmdline += " -j"; cmdline += QString::number(jobs); } if (DomUtil::readBoolEntry(dom, "/kdevautoproject/make/dontact")) cmdline += " -n"; cmdline += " "; cmdline += target; cmdline.prepend(nice); cmdline.prepend(makeEnvironment()); QString dircmd = "cd "; dircmd += KProcess::quote(dir); dircmd += " && "; return preCommand + dircmd + cmdline; } void AutoProjectPart::startMakeCommand(const QString &dir, const QString &target, bool withKdesu) { if (partController()->saveAllFiles()==false) return; //user cancelled kdDebug(9020) << "startMakeCommand:" << dir << ": "<< target << endl; m_buildCommand = constructMakeCommandLine(dir, target); if (withKdesu) m_buildCommand = "kdesu -t -c '" + m_buildCommand + "'"; if (!m_buildCommand.isNull()) makeFrontend()->queueCommand(dir, m_buildCommand); } /** Adds the make command for the libraries that the target depends on * to the make frontend queue (this is a recursive function) */ bool AutoProjectPart::queueInternalLibDependenciesBuild(TargetItem* titem, QStringList& alreadyScheduledDeps) { QString addstr = (titem->primary == "PROGRAMS")? titem->ldadd : titem->libadd; QStringList l2 = QStringList::split(QRegExp("[ \t]"), addstr); // list of dependencies QString tdir; // temp target directory QString tname; // temp target name QString tcmd; // temp command line QStringList::Iterator l2it; for (l2it = l2.begin(); l2it != l2.end(); ++l2it) { QString dependency = *l2it; if (dependency.startsWith("$(top_builddir)/")) { // These are the internal libraries dependency.remove("$(top_builddir)/"); if( !alreadyScheduledDeps.contains(*l2it) ) { alreadyScheduledDeps << *l2it; tdir = buildDirectory(); if (!tdir.endsWith("/") && !tdir.isEmpty()) tdir += "/"; int pos = dependency.findRev('/'); if (pos == -1) { tname = dependency; } else { tdir += dependency.left(pos+1); tname = dependency.mid(pos+1); } kdDebug(9020) << "Scheduling : <" << tdir << "> target <" << tname << ">" << endl; // Recursively queue the dependencies for building SubprojectItem *spi = m_widget->subprojectItemForPath( dependency.left(pos) ); if (spi) { QPtrList< TargetItem > tl = spi->targets; // Cycle through the list of targets to find the one we're looking for TargetItem *ti = tl.first(); do { if (ti->name == tname) { // found it: queue it and stop looking if( !queueInternalLibDependenciesBuild(ti, alreadyScheduledDeps) ) return false; break; } ti = tl.next(); } while (ti); } kdDebug(9020) << "queueInternalLibDependenciesBuild:" << tdir << ": "<< tname << endl; tcmd = constructMakeCommandLine(tdir, tname); if (!tcmd.isNull()) { makeFrontend()->queueCommand( tdir, tcmd); } }else { //Message box about circular deps. tdir = buildDirectory(); if (!tdir.endsWith("/") && !tdir.isEmpty()) tdir += "/"; int pos = dependency.findRev('/'); if (pos == -1) { tname = dependency; } else { tdir += dependency.left(pos+1); tname = dependency.mid(pos+1); } KMessageBox::error( 0, i18n("Found a circular dependency in the project, between this target and %1.\nCannot build this project until this is resolved.").arg(tname), i18n("Circular Dependency found") ); return false; } } } return true; } void AutoProjectPart::slotBuild() { //m_lastCompilationFailed = false; if( m_needMakefileCvs ) { slotMakefilecvs(); slotConfigure(); m_needMakefileCvs = false; } startMakeCommand(buildDirectory(), QString::fromLatin1("")); } void AutoProjectPart::buildTarget(QString relpath, TargetItem* titem) { if ( !titem ) return; //m_lastCompilationFailed = false; // Calculate the complete name of the target and store it in name QString name = titem->name; if ( titem->primary == "KDEDOCS" ) name = "index.cache.bz2"; // Calculate the full path of the target and store it in path QString path = buildDirectory(); if (!path.endsWith("/") && !path.isEmpty()) path += "/"; if (relpath.at(0) == '/') path += relpath.mid(1); else path += relpath; // Save all files once partController()->saveAllFiles(); // Add the make command for the libraries that the target depends on to the make frontend queue // if this recursive behavour is un-wanted comment the next line QStringList deps; if( !queueInternalLibDependenciesBuild(titem, deps) ) return; // Calculate the "make" command line for the target //QString relpath = dir.path().mid( projectDirectory().length() ); m_runProg=buildDirectory() + "/" + relpath+"/"+name; kdDebug(9020) << "buildTarget:" << buildDirectory()<< endl; kdDebug(9020) << "buildTarget:" << relpath << " " << path << ": "<< name << " : " << m_runProg << endl; QString tcmd = constructMakeCommandLine( path, name ); // Call make if (!tcmd.isNull()) { m_buildCommand = tcmd; makeFrontend()->queueCommand( path, tcmd); } } void AutoProjectPart::slotBuildActiveTarget() { // Get a pointer to the active target TargetItem* titem = m_widget->activeTarget(); if ( !titem ) return; // build it buildTarget( URLUtil::getRelativePath( topsourceDirectory(), projectDirectory() ) + "/" + activeDirectory(), titem); } void AutoProjectPart::slotCompileFile() { KParts::ReadWritePart *part = dynamic_cast(partController()->activePart()); if (!part || !part->url().isLocalFile()) return; QString fileName = part->url().path(); QFileInfo fi(fileName); QString sourceDir = fi.dirPath(); QString baseName = fi.baseName(true); kdDebug(9020) << "Compiling " << fileName << " in dir " << sourceDir << " with baseName " << baseName << endl; QString projectDir = projectDirectory(); if (!sourceDir.startsWith(projectDir)) { KMessageBox::sorry(m_widget, i18n("Can only compile files in directories which belong to the project.")); return; } QString buildDir = buildDirectory() + sourceDir.mid(projectDir.length()); QString target = baseName + ".lo"; kdDebug(9020) << "builddir " << buildDir << ", target " << target << endl; startMakeCommand(buildDir, target); } QString AutoProjectPart::configureCommand() const { QDomDocument &dom = *projectDom(); QString prefix = "/kdevautoproject/configurations/" + currentBuildConfig() + "/"; QString cmdline = "\"" + topsourceDirectory(); cmdline += "/configure\""; QString cc = DomUtil::readEntry(dom, prefix + "ccompilerbinary"); if (!cc.isEmpty()) cmdline.prepend(QString("CC=%1 ").arg(cc)); QString cflags = DomUtil::readEntry(dom, prefix + "cflags"); if (!cflags.isEmpty()) cmdline.prepend(QString("CFLAGS=\"%1\" ").arg(cflags)); QString cxx = DomUtil::readEntry(dom, prefix + "cxxcompilerbinary"); if (!cxx.isEmpty()) cmdline.prepend(QString("CXX=%1 ").arg(cxx)); QString cxxflags = DomUtil::readEntry(dom, prefix + "cxxflags"); if (!cxxflags.isEmpty()) cmdline.prepend(QString("CXXFLAGS=\"%1\" ").arg(cxxflags)); QString f77 = DomUtil::readEntry(dom, prefix + "f77compilerbinary"); if (!f77.isEmpty()) cmdline.prepend(QString("F77=%1 ").arg(f77)); QString fflags = DomUtil::readEntry(dom, prefix + "f77flags"); if (!fflags.isEmpty()) cmdline.prepend(QString("FFLAGS=\"%1\" ").arg(fflags)); QString cppflags = DomUtil::readEntry(dom, prefix + "cppflags"); if (!cppflags.isEmpty()) cmdline.prepend(QString("CPPFLAGS=\"%1\" ").arg(cppflags)); QString ldflags = DomUtil::readEntry(dom, prefix + "ldflags"); if (!ldflags.isEmpty()) cmdline.prepend(QString("LDFLAGS=\"%1\" ").arg(ldflags)); QString configargs = DomUtil::readEntry(dom, prefix + "configargs"); if (!configargs.isEmpty()) { cmdline += " "; cmdline += configargs; } DomUtil::PairList envvars = DomUtil::readPairListEntry(*projectDom(), prefix + "envvars", "envvar", "name", "value"); QString environstr; DomUtil::PairList::ConstIterator it; for (it = envvars.begin(); it != envvars.end(); ++it) { environstr += (*it).first; environstr += "="; environstr += EnvVarTools::quote((*it).second); environstr += " "; } cmdline.prepend(environstr); QString builddir = buildDirectory(); QString dircmd; // if the build directory doesn't exist, add it's creation to the configureCommand if ( !QFile::exists(builddir)) { dircmd = "mkdir "; dircmd += KProcess::quote(builddir); dircmd += " && "; } // add "cd into the build directory" to the configureCommand dircmd += "cd "; dircmd += KProcess::quote(builddir); dircmd += " && "; return dircmd + cmdline; } void AutoProjectPart::slotConfigure() { QString cmdline = configureCommand(); if (cmdline.isNull()) return; makeFrontend()->queueCommand(buildDirectory(), cmdline); } QString AutoProjectPart::makefileCvsCommand() const { kdDebug(9020) << "makefileCvsCommand: runDirectory :" << runDirectory() << ":" <queueCommand(projectDirectory(), cmdline); } void AutoProjectPart::slotInstall() { startMakeCommand(buildDirectory(), QString::fromLatin1("install")); } void AutoProjectPart::slotInstallWithKdesu() { // First issue "make" to build the entire project with the current user // This way we make sure all files are up to date before we do the "make install" slotBuild(); // After that issue "make install" with the root user startMakeCommand(buildDirectory(), QString::fromLatin1("install"), true); } void AutoProjectPart::slotClean() { startMakeCommand(buildDirectory(), QString::fromLatin1("clean")); } void AutoProjectPart::slotDistClean() { startMakeCommand(buildDirectory(), QString::fromLatin1("distclean")); } void AutoProjectPart::slotMakeMessages() { startMakeCommand(buildDirectory(), QString::fromLatin1("package-messages")); } /** Checks if the currently selected main program or, * if no main Program was selected in the Run Options dialog, * the currently active target is up-to-date and builds it if necessary. * In the end checks if the program is already running and if not calls the * slotExecute2() function to execute it or asks the user what to do. */ void AutoProjectPart::slotExecute() { partController()->saveAllFiles(); QDomDocument &dom = *projectDom(); m_runProg=m_runProg.isEmpty()?mainProgram():m_runProg; bool _auto = false; if( DomUtil::readBoolEntry(dom, "/kdevautoproject/run/autocompile", true) && isDirty() ){ m_executeAfterBuild = true; if ( DomUtil::readBoolEntry(dom, "/kdevautoproject/run/useglobalprogram", false) ){ // A Main Program was specified, build all targets because we don't know which is it kdDebug(9020) << "slotExecute: before slotBuild" << endl; slotBuild(); } else{ // If no Main Program was specified, build the active target kdDebug(9020) << "slotExecute: before slotBuildActiveTarget" << endl; slotBuildActiveTarget(); } _auto = true; } if( DomUtil::readBoolEntry(dom, "/kdevautoproject/run/autoinstall", false) && isDirty() ){ m_executeAfterBuild = true; // Use kdesu?? if( DomUtil::readBoolEntry(dom, "/kdevautoproject/run/autokdesu", false) ){ //slotInstallWithKdesu assumes that it hasn't just been build... kdDebug(9020) << "slotExecute: before startMakeCommand" << endl; _auto ? slotInstallWithKdesu() : startMakeCommand(buildDirectory(), QString::fromLatin1("install"), true); } else{ kdDebug(9020) << "slotExecute: before slotInstall" << endl; slotInstall(); } _auto = true; } if ( _auto ){ m_runProg.truncate(0); return; } if (appFrontend()->isRunning()) { if (KMessageBox::questionYesNo(m_widget, i18n("Your application is currently running. Do you want to restart it?"), i18n("Application Already Running"), i18n("&Restart Application"), i18n("Do &Nothing")) == KMessageBox::No) return; connect(appFrontend(), SIGNAL(processExited()), SLOT(slotExecute2())); appFrontend()->stopApplication(); return; } kdDebug(9020) << "slotExecute: before slotExecute2" << endl; slotExecute2(); } void AutoProjectPart::executeTarget(const QDir& dir, const TargetItem* titem) { m_executeAfterBuild=true; partController()->saveAllFiles(); bool is_dirty = false; QDateTime t = QFileInfo(dir , titem->name ).lastModified(); QPtrListIterator it( titem->sources ); for( ; it.current() ; ++it ) { if( t < QFileInfo(dir , (*it)->name).lastModified()) is_dirty = true; } if( DomUtil::readBoolEntry(*projectDom(), "/kdevautoproject/run/autocompile", true) && is_dirty ) { connect( makeFrontend(), SIGNAL(commandFinished(const QString&)), this, SLOT(slotExecuteTargetAfterBuild(const QString&)) ); connect( makeFrontend(), SIGNAL(commandFailed(const QString&)), this, SLOT(slotNotExecuteTargetAfterBuildFailed(const QString&)) ); m_runProg=titem->name; m_executeTargetAfterBuild.first = dir; m_executeTargetAfterBuild.second = const_cast(titem); QString relpath = "/" + URLUtil::getRelativePath( topsourceDirectory(), projectDirectory() ) + "/" + m_widget->selectedSubproject()->subdir; kdDebug(9020) << "executeTarget: before buildTarget " << relpath << endl; buildTarget(relpath, const_cast(titem)); return; } bool inTerminal = DomUtil::readBoolEntry(*projectDom(), "/kdevautoproject/run/terminal"); QString program = environString(); if ( !titem ) { KMessageBox::error( m_widget, i18n("There is no active target.\n" "Unable to determine the main program"), i18n("No active target found") ); kdDebug ( 9020 ) << k_funcinfo << "Error! : There's no active target! -> Unable to determine the main program in AutoProjectPart::mainProgram()" << endl; program += titem->name; }else if ( titem->primary != "PROGRAMS" ) { KMessageBox::error( m_widget, i18n("Active target \"%1\" is not binary ( %2 ).\n" "Unable to determine the main program. If you want this\n" "to be the active target, set a main program under\n" "Project -> Project Options -> Run Options").arg(titem->name).arg(titem->primary), i18n("Active target is not a library") ); kdDebug ( 9020 ) << k_funcinfo << "Error! : Active target isn't binary (" << titem->primary << ") ! -> Unable to determine the main program in AutoProjectPart::mainProgram()" << endl; program += titem->name; }else program += buildDirectory() + "/" + URLUtil::getRelativePath( topsourceDirectory(), projectDirectory() ) + "/" + m_widget->selectedSubproject()->relativePath()+ "/" + titem->name; QString args = DomUtil::readEntry(*projectDom(), "/kdevautoproject/run/runarguments/" + titem->name); program += " " + args; kdDebug(9020) << "executeTarget:cmd=" << dir.path() << " " << program << endl; appFrontend()->startAppCommand(dir.path(), program ,inTerminal); m_executeAfterBuild=false; } void AutoProjectPart::slotExecuteTargetAfterBuild(const QString& command) { kdDebug(9020) << "slotExecuteTargetAfterBuild " << command << endl; if ( m_executeAfterBuild && constructMakeCommandLine(m_executeTargetAfterBuild.first.path(), m_executeTargetAfterBuild.second->name) == command ) { disconnect( makeFrontend(), SIGNAL(commandFinished(const QString&)), this, SLOT(slotExecuteAfterTargetBuild()) ); disconnect( makeFrontend(), SIGNAL(commandFailed(const QString&)), this, SLOT(slotExecuteAfterTargetBuildFailed()) ); kdDebug(9020) << "slotExecuteTargetAfterBuild " << endl; executeTarget(m_executeTargetAfterBuild.first, m_executeTargetAfterBuild.second); } } void AutoProjectPart::slotNotExecuteTargetAfterBuildFailed(const QString& command) { kdDebug(9020) << "executeTargetAfterBuildFailed" << endl; if ( constructMakeCommandLine(m_executeTargetAfterBuild.first.path(), m_executeTargetAfterBuild.second->name) == command ) { m_executeAfterBuild=false; disconnect( makeFrontend(), SIGNAL(commandFinished(const QString&)), this, SLOT(slotExecuteTargetAfterBuild()) ); disconnect( makeFrontend(), SIGNAL(commandFailed(const QString&)), this, SLOT(slotNotExecuteTargetAfterBuildFailed()) ); } } /* Get the run environment variables pairs into the environstr string * in the form of: "ENV_VARIABLE=ENV_VALUE" * Note that we quote the variable value due to the possibility of * embedded spaces. */ QString AutoProjectPart::environString() const { DomUtil::PairList envvars = runEnvironmentVars(); QString environstr; DomUtil::PairList::ConstIterator it; for (it = envvars.begin(); it != envvars.end(); ++it) { environstr += (*it).first; environstr += "="; environstr += EnvVarTools::quote((*it).second); environstr += " "; } return environstr; } /** Executes the currently selected main program. * If no main Program was selected in the Run Options dialog * the currently active target is executed instead. */ void AutoProjectPart::slotExecute2() { disconnect(appFrontend(), SIGNAL(processExited()), this, SLOT(slotExecute2())); if (m_runProg.isEmpty()){ // Do not execute non executable targets return; } QString program = environString(); // Adds the ./ that is necessary to execute the program in bash shells if (!m_runProg.startsWith("/")){ program += "./"; } program += m_runProg; program += " " + runArguments(); bool inTerminal = DomUtil::readBoolEntry(*projectDom(), "/kdevautoproject/run/terminal"); kdDebug(9020) << "slotExecute2: runDirectory: <" << runDirectory() << ">" <" <" <" <" <startAppCommand(runDirectory(), program, inTerminal); m_executeAfterBuild=false; m_runProg.truncate(0); } void AutoProjectPart::slotAddTranslation() { AddTranslationDialog dlg(this, m_widget); dlg.exec(); } void AutoProjectPart::slotBuildConfigChanged(const QString &config) { DomUtil::writeEntry(*projectDom(), "/kdevautoproject/general/useconfiguration", config); kdDebug(9020) << "Changed used configuration to " << config << endl; } void AutoProjectPart::slotBuildConfigAboutToShow() { QStringList l = allBuildConfigs(); buildConfigAction->setItems(l); buildConfigAction->setCurrentItem(l.findIndex(currentBuildConfig())); } void AutoProjectPart::restorePartialProjectSession ( const QDomElement* el ) { m_widget->restoreSession ( el ); } void AutoProjectPart::savePartialProjectSession ( QDomElement* el ) { QDomDocument domDoc = el->ownerDocument(); KMessageBox::information ( 0, "Hallo, Welt!" ); kdDebug ( 9020 ) << k_funcinfo << "1" << endl; if ( domDoc.isNull() ) { kdDebug ( 9020 ) << k_funcinfo << "2" << endl; return; } kdDebug ( 9020 ) << k_funcinfo << "3" << endl; m_widget->saveSession ( el ); } void AutoProjectPart::slotCommandFinished( const QString& command ) { kdDebug(9020) << k_funcinfo << endl; if( m_buildCommand != command ) return; m_buildCommand = QString::null; m_timestamp.clear(); QStringList fileList = allFiles(); QStringList::Iterator it = fileList.begin(); while( it != fileList.end() ){ QString fileName = *it; ++it; m_timestamp[ fileName ] = QFileInfo( projectDirectory(), fileName ).lastModified(); } emit projectCompiled(); // reset the "last compilation has failed" flag m_lastCompilationFailed = false; if( m_executeAfterBuild ){ slotExecute(); } } void AutoProjectPart::slotCommandFailed( const QString& /*command*/ ) { kdDebug(9020) << "slotCommandFinished " << k_funcinfo << endl; m_lastCompilationFailed = true; m_executeAfterBuild=false; } bool AutoProjectPart::isDirty() { if (m_lastCompilationFailed) return true; QStringList fileList = allFiles(); QStringList::Iterator it = fileList.begin(); while( it != fileList.end() ){ QString fileName = *it; ++it; QMap::Iterator it = m_timestamp.find( fileName ); QDateTime t = QFileInfo( projectDirectory(), fileName ).lastModified(); if( it == m_timestamp.end() || *it != t ){ return true; } } return false; } void AutoProjectPart::needMakefileCvs( ) { m_needMakefileCvs = true; } bool AutoProjectPart::isKDE() const { return m_isKDE; } KDevProject::Options AutoProjectPart::options() const { return UsesAutotoolsBuildSystem; } QStringList recursiveATFind( const QString &currDir, const QString &baseDir ) { kdDebug(9020) << "Dir " << currDir << endl; QStringList fileList; if( !currDir.contains( "/..") && !currDir.contains("/.") ) { QDir dir(currDir); QStringList dirList = dir.entryList(QDir::Dirs ); QStringList::Iterator idx = dirList.begin(); for( ; idx != dirList.end(); ++idx ) { fileList += recursiveATFind( currDir + "/" + (*idx),baseDir ); } QStringList newFiles = dir.entryList("*.am *.in"); idx = newFiles.begin(); for( ; idx != newFiles.end(); ++idx ) { QString file = currDir + "/" + (*idx); fileList.append( file.remove( baseDir ) ); } } return fileList; } /*! \fn AutoProjectPart::distFiles() const */ QStringList AutoProjectPart::distFiles() const { QStringList sourceList = allFiles(); // Scan current source directory for any .pro files. QString projectDir = projectDirectory(); QDir dir(projectDir); QDir admin(projectDir +"/admin"); QStringList files = dir.entryList( "Makefile.cvs Makefile.am configure* INSTALL README NEWS TODO ChangeLog COPYING AUTHORS stamp-h.in acinclude.m4 config.h.in Makefile.in install-sh config.sub config.guess mkinstalldirs missing ltmain.sh depcomp"); QStringList adminFiles = admin.entryList(QDir::Files); QStringList::Iterator idx = adminFiles.begin(); for( ; idx != adminFiles.end(); ++idx) { files.append( "admin/" + (*idx) ); } QStringList srcDirs = dir.entryList(QDir::Dirs); idx = srcDirs.begin(); for(; idx != srcDirs.end(); ++idx) { sourceList += recursiveATFind( projectDirectory() + "/" + (*idx), projectDirectory()); } return sourceList + files; } void AutoProjectPart::startSimpleMakeCommand( const QString & dir, const QString & command, bool withKdesu ) { if (partController()->saveAllFiles()==false) return; //user cancelled // m_buildCommand = constructMakeCommandLine(dir, target); QString cmdline = command; cmdline.prepend(makeEnvironment()); QString dircmd = "cd "; dircmd += KProcess::quote(dir); dircmd += " && "; m_buildCommand = dircmd + cmdline; if (withKdesu) m_buildCommand = "kdesu -t -c '" + m_buildCommand + "'"; if (!m_buildCommand.isNull()) makeFrontend()->queueCommand(dir, m_buildCommand); } QString AutoProjectPart::getAutoConfFile(const QString& dir){ QFile inFile(dir + "/configure.in"); QFile acFile(dir + "/configure.ac"); if ( inFile.exists()){ return inFile.name(); }else if (acFile.exists()){ return acFile.name(); } return acFile.name();; } #include "autoprojectpart.moc" // kate: space-indent on; indent-width 4;