1
/* This file is part of KDevelop
2
Copyright 2004 Roberto Raggi <roberto@kdevelop.org>
3
Copyright 2007 Andreas Pakulat <apaku@gmx.de>
4
Copyright 2007 Dukju Ahn <dukjuahn@gmail.com>
5
Copyright 2008 Hamish Rodda <rodda@kde.org>
7
This library is free software; you can redistribute it and/or
8
modify it under the terms of the GNU Library General Public
9
License as published by the Free Software Foundation; either
10
version 2 of the License, or (at your option) any later version.
12
This library is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
Library General Public License for more details.
17
You should have received a copy of the GNU Library General Public License
18
along with this library; see the file COPYING.LIB. If not, write to
19
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20
Boston, MA 02110-1301, USA.
25
#include <QtCore/QStringList>
26
#include <QtCore/QProcess>
34
#include <interfaces/icore.h>
35
#include <interfaces/iplugincontroller.h>
36
#include <util/environmentgrouplist.h>
37
#include <project/projectmodel.h>
38
#include <project/interfaces/ibuildsystemmanager.h>
39
#include <util/processlinemaker.h>
40
#include <interfaces/iproject.h>
42
#include "makeoutputdelegate.h"
43
#include "makeoutputmodel.h"
44
#include "makebuilder.h"
46
using namespace KDevelop;
48
MakeJob::MakeJob(MakeBuilder* builder, KDevelop::ProjectBaseItem* item, CommandType c, const QString& overrideTarget )
53
, m_overrideTarget(overrideTarget)
59
setCapabilities(Killable);
62
if( !m_overrideTarget.isEmpty() )
63
title = i18n("Make: %1", m_overrideTarget);
65
title = i18n("Make: %1", m_item->text());
73
kDebug(9037) << "Building with make" << m_command << m_overrideTarget;
75
if( m_item->type() == KDevelop::ProjectBaseItem::File ) {
76
setError(IncorrectItemError);
77
setErrorText("Internal error: cannot build a file item");
81
KUrl buildDir = computeBuildDir(m_item);
82
if( !buildDir.isValid() ) {
83
setError(InvalidBuildDirectoryError);
84
setErrorText(i18n("Invalid build directory '%1'", buildDir.prettyUrl()));
88
QStringList cmd = computeBuildCommand();
90
setError(BuildCommandError);
91
setErrorText(i18n("Could not create build command for target '%1'", m_overrideTarget));
95
setStandardToolView(IOutputView::BuildView);
96
setBehaviours(KDevelop::IOutputView::AllowUserClose | KDevelop::IOutputView::AutoScroll);
98
setModel(new MakeOutputModel(buildDir), IOutputView::TakeOwnership);
99
setDelegate(m_builder->delegate());
103
model()->addLine( buildDir.toLocalFile() + "> " + cmd.join(" ") );
105
QString command = cmd.first();
108
m_process = new KProcess(this);
109
m_process->setOutputChannelMode( KProcess::MergedChannels );
110
m_lineMaker = new ProcessLineMaker( m_process );
111
connect( m_lineMaker, SIGNAL(receivedStdoutLines( const QStringList& ) ),
112
this, SLOT( addStandardOutput( const QStringList& ) ) );
113
connect( m_process, SIGNAL( error( QProcess::ProcessError ) ),
114
this, SLOT( procError( QProcess::ProcessError ) ) );
115
connect( m_process, SIGNAL( finished( int, QProcess::ExitStatus ) ),
116
this, SLOT( procFinished( int, QProcess::ExitStatus ) ) );
118
m_process->setEnvironment( environmentVars() );
119
m_process->setWorkingDirectory( buildDir.toLocalFile() );
120
m_process->setProgram( command, cmd );
121
kDebug(9037) << "Starting build:" << cmd << "Build directory" << buildDir;
125
KDevelop::ProjectBaseItem * MakeJob::item() const
130
MakeJob::CommandType MakeJob::commandType()
135
const QString & MakeJob::customTarget() const
137
return m_overrideTarget;
140
KUrl MakeJob::computeBuildDir(KDevelop::ProjectBaseItem* item) const
143
KDevelop::IBuildSystemManager *bldMan = item->project()->buildSystemManager();
145
buildDir = bldMan->buildDirectory( item ); // the correct build dir
148
switch( item->type() )
150
case KDevelop::ProjectBaseItem::Folder:
151
case KDevelop::ProjectBaseItem::BuildFolder:
152
return static_cast<KDevelop::ProjectFolderItem*>(item)->url();
154
case KDevelop::ProjectBaseItem::Target:
155
case KDevelop::ProjectBaseItem::File:
156
buildDir = computeBuildDir( static_cast<KDevelop::ProjectBaseItem*>( item->parent() ) );
163
QStringList MakeJob::computeBuildCommand() const
166
// QString cmdline = DomUtil::readEntry(dom, makeTool);
167
// int prio = DomUtil::readIntEntry(dom, priority);
170
// nice = QString("nice -n%1 ").arg(prio);
173
KSharedConfig::Ptr configPtr = m_item->project()->projectConfiguration();
174
KConfigGroup builderGroup( configPtr, "MakeBuilder" );
176
QString makeBin = builderGroup.readEntry("Make Binary", "make");
179
if( ! builderGroup.readEntry("Abort on First Error", true) )
184
int jobnumber = builderGroup.readEntry("Number Of Jobs", 1);
186
QString jobNumberArg = QString("-j%1").arg(jobnumber);
187
cmdline << jobNumberArg;
190
if( builderGroup.readEntry("Display Only", false) )
194
QString extraOptions = builderGroup.readEntry("Additional Options", QString());
195
if( ! extraOptions.isEmpty() )
197
foreach(const QString& option, KShell::splitArgs( extraOptions ) )
201
if( m_overrideTarget.isEmpty() )
204
switch (m_item->type()) {
205
case KDevelop::ProjectBaseItem::Target:
206
case KDevelop::ProjectBaseItem::ExecutableTarget:
207
case KDevelop::ProjectBaseItem::LibraryTarget:
208
Q_ASSERT(m_item->target());
209
cmdline << m_item->target()->text();
211
case KDevelop::ProjectBaseItem::BuildFolder:
212
target = builderGroup.readEntry("Default Target", QString());
213
if( !target.isEmpty() )
219
cmdline << m_overrideTarget;
222
bool runAsRoot = builderGroup.readEntry("Install As Root", false);
223
if (runAsRoot && m_command == InstallCommand)
225
int suCommand = builderGroup.readEntry("Su Command", 0);
226
QStringList kdesuline;
227
kdesuline << ((suCommand == 0) ? "kdesu" : "kdesudo" ) << "-t" << "-c" << cmdline.join(" ");
234
QStringList MakeJob::environmentVars() const
236
KSharedConfig::Ptr configPtr = m_item->project()->projectConfiguration();
237
KConfigGroup builderGroup( configPtr, "MakeBuilder" );
238
QString defaultProfile = builderGroup.readEntry(
239
"Default Make Environment Profile", "default" );
241
const KDevelop::EnvironmentGroupList l(KGlobal::config());
242
QStringList env = QProcess::systemEnvironment();
243
QStringList::iterator it, end = env.end();
244
for( it = env.begin(); it != end; it++ ) {
245
if( (*it).startsWith("LC_MESSAGES") || (*it).startsWith("LC_ALL") ) {
249
env.append( "LC_MESSAGES=C" );
250
return l.createEnvironment( defaultProfile, env );
253
void MakeJob::addStandardOutput( const QStringList& lines )
255
model()->addLines( lines );
258
void MakeJob::procError( QProcess::ProcessError err )
260
//This slot might be called twice for a given process, once when a real error
261
//occurs and then again when the process has exited due to the error
262
//via procFinished() slot. So make sure we run the code only once.
268
m_lineMaker->flushBuffers();
271
setError(FailedError);
272
setErrorText(i18n("Job failed"));
273
model()->addLine( i18n("*** Failed ***") );
278
void MakeJob::procFinished( int code, QProcess::ExitStatus status )
281
m_lineMaker->flushBuffers();
282
if( code==0 && status == QProcess::NormalExit )
284
model()->addLine( i18n("*** Finished ***") );
289
procError(QProcess::UnknownError);
293
bool MakeJob::doKill()
295
model()->addLine( i18n("*** Aborted ***") );
301
MakeOutputModel* MakeJob::model() const
303
return dynamic_cast<MakeOutputModel*>( OutputJob::model() );
306
void MakeJob::setItem( ProjectBaseItem* item )
312
#include "makejob.moc"