~ubuntu-branches/ubuntu/hardy/codeblocks/hardy-backports

« back to all changes in this revision

Viewing changes to src/sdk/compiler.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michael Casadevall
  • Date: 2008-07-17 04:39:23 UTC
  • Revision ID: james.westby@ubuntu.com-20080717043923-gmsy5cwkdjswghkm
Tags: upstream-8.02
ImportĀ upstreamĀ versionĀ 8.02

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * This file is part of the Code::Blocks IDE and licensed under the GNU Lesser General Public License, version 3
 
3
 * http://www.gnu.org/licenses/lgpl-3.0.html
 
4
 *
 
5
 * $Revision: 4909 $
 
6
 * $Id: compiler.cpp 4909 2008-02-27 13:15:26Z mortenmacfly $
 
7
 * $HeadURL: svn://svn.berlios.de/codeblocks/tags/8.02/src/sdk/compiler.cpp $
 
8
 */
 
9
 
 
10
#include "sdk_precomp.h"
 
11
 
 
12
#ifndef CB_PRECOMP
 
13
    #include "cbexception.h"
 
14
    #include "compiler.h"
 
15
    #include "manager.h"
 
16
    #include "logmanager.h"
 
17
    #include "configmanager.h"
 
18
    #include "macrosmanager.h"
 
19
    #include "globals.h"
 
20
    #include "compilerfactory.h"
 
21
 
 
22
    #include <wx/intl.h>
 
23
    #include <wx/regex.h>
 
24
#endif
 
25
 
 
26
#include "compilercommandgenerator.h"
 
27
#include <wx/filefn.h>
 
28
#include <wx/arrimpl.cpp>
 
29
WX_DEFINE_OBJARRAY(RegExArray);
 
30
 
 
31
// static
 
32
wxArrayString Compiler::m_CompilerIDs; // map to guarantee unique IDs
 
33
 
 
34
// common regex that can be used by the different compiler for matching compiler output
 
35
// it can be used in the patterns for warnings, errors, ...
 
36
// NOTE : it is an approximation (for example the ':' can appear anywhere and several times)
 
37
const wxString Compiler::FilePathWithSpaces = _T("[][{}() \t#%$~A-Za-z0-9_:+/\\.-]+");
 
38
 
 
39
// version of compiler settings
 
40
// when this is different from what is saved in the config, a message appears
 
41
// to the user saying that default settings have changed and asks him if he wants to
 
42
// use his own settings or the new defaults
 
43
const wxString CompilerSettingsVersion = _T("0.0.2");
 
44
 
 
45
CompilerSwitches::CompilerSwitches()
 
46
{   // default based upon gnu
 
47
    includeDirs = _T("-I");
 
48
    libDirs = _T("-L");
 
49
    linkLibs = _T("-l");
 
50
    defines = _T("-D");
 
51
    genericSwitch = _T("-");
 
52
    objectExtension = _T("o");
 
53
    needDependencies = true;
 
54
    forceFwdSlashes = false;
 
55
    forceCompilerUseQuotes = false;
 
56
    forceLinkerUseQuotes = false;
 
57
    logging = clogSimple;
 
58
    libPrefix = _T("lib");
 
59
    libExtension = _T("a");
 
60
    linkerNeedsLibPrefix = false;
 
61
    linkerNeedsLibExtension = false;
 
62
    supportsPCH = true;
 
63
    PCHExtension = _T("h.gch");
 
64
    UseFlatObjects = false;
 
65
    UseFullSourcePaths = false;
 
66
} // end of constructor
 
67
 
 
68
 
 
69
wxString Compiler::CommandTypeDescriptions[ctCount] =
 
70
{
 
71
    // These are the strings that describe each CommandType enumerator...
 
72
    // No need to say that it must have the same order as the enumerators!
 
73
    _("Compile single file to object file"),
 
74
    _("Generate dependencies for file"),
 
75
    _("Compile Win32 resource file"),
 
76
    _("Link object files to executable"),
 
77
    _("Link object files to console executable"),
 
78
    _("Link object files to dynamic library"),
 
79
    _("Link object files to static library"),
 
80
    _("Link object files to native executable")
 
81
};
 
82
 
 
83
Compiler::Compiler(const wxString& name, const wxString& ID, const wxString& parentID)
 
84
    : m_Name(name),
 
85
    m_ID(ID.Lower()),
 
86
    m_ParentID(parentID.Lower()),
 
87
    m_pGenerator(0),
 
88
    m_Valid(false),
 
89
    m_NeedValidityCheck(true),
 
90
    m_Mirrored(false)
 
91
{
 
92
    //ctor
 
93
    MakeValidID();
 
94
 
 
95
    m_Switches.supportsPCH = false;
 
96
    m_Switches.forceFwdSlashes = false;
 
97
    m_VersionString = wxEmptyString;
 
98
 
 
99
    Manager::Get()->GetLogManager()->DebugLog(F(_T("Added compiler \"%s\""), m_Name.c_str()));
 
100
}
 
101
 
 
102
Compiler::Compiler(const Compiler& other)
 
103
    : CompileOptionsBase(other),
 
104
    m_ParentID(other.m_ParentID.IsEmpty() ? other.m_ID : other.m_ParentID),
 
105
    m_pGenerator(0),
 
106
    m_Mirror(other.m_Mirror),
 
107
    m_Mirrored(other.m_Mirrored)
 
108
{
 
109
    m_Name = _("Copy of ") + other.m_Name;
 
110
    // generate unique ID
 
111
    // note that this copy constructor is protected and can only be called
 
112
    // by our friend CompilerFactory. It knows what it's doing ;)
 
113
    wxDateTime now = wxDateTime::UNow();
 
114
    m_ID = now.Format(_T("%c"), wxDateTime::CET);
 
115
    MakeValidID();
 
116
 
 
117
    m_MasterPath = other.m_MasterPath;
 
118
    m_Programs = other.m_Programs;
 
119
    m_Switches = other.m_Switches;
 
120
    m_Options = other.m_Options;
 
121
    m_IncludeDirs = other.m_IncludeDirs;
 
122
    m_LibDirs = other.m_LibDirs;
 
123
    m_CompilerOptions = other.m_CompilerOptions;
 
124
    m_LinkerOptions = other.m_LinkerOptions;
 
125
    m_LinkLibs = other.m_LinkLibs;
 
126
    m_CmdsBefore = other.m_CmdsBefore;
 
127
    m_CmdsAfter = other.m_CmdsAfter;
 
128
    m_RegExes = other.m_RegExes;
 
129
    m_VersionString = other.m_VersionString;
 
130
    for (int i = 0; i < ctCount; ++i)
 
131
    {
 
132
        m_Commands[(CommandType)i] = other.m_Commands[(CommandType)i];
 
133
    }
 
134
 
 
135
    m_Valid = other.m_Valid;
 
136
    m_NeedValidityCheck = other.m_NeedValidityCheck;
 
137
}
 
138
 
 
139
Compiler::~Compiler()
 
140
{
 
141
    //dtor
 
142
    delete m_pGenerator;
 
143
}
 
144
 
 
145
bool Compiler::IsValid()
 
146
{
 
147
    if (!m_NeedValidityCheck)
 
148
        return m_Valid;
 
149
 
 
150
    if (m_MasterPath.IsEmpty())
 
151
        return true; // still initializing, don't try to test now
 
152
 
 
153
    m_NeedValidityCheck = false;
 
154
 
 
155
    if (!SupportsCurrentPlatform())
 
156
    {
 
157
        m_Valid = false;
 
158
        return false;
 
159
    }
 
160
 
 
161
    wxString tmp = m_MasterPath + _T("/bin/") + m_Programs.C;
 
162
    Manager::Get()->GetMacrosManager()->ReplaceMacros(tmp);
 
163
    m_Valid = wxFileExists(tmp);
 
164
    if (!m_Valid)
 
165
    {   // and try witout appending the 'bin'
 
166
        tmp = m_MasterPath + _T("/") + m_Programs.C;
 
167
        Manager::Get()->GetMacrosManager()->ReplaceMacros(tmp);
 
168
        m_Valid = wxFileExists(tmp);
 
169
    }
 
170
    if (!m_Valid)
 
171
    {
 
172
        // look in extra paths too
 
173
        for (size_t i = 0; i < m_ExtraPaths.GetCount(); ++i)
 
174
        {
 
175
            tmp = m_ExtraPaths[i] + _T("/") + m_Programs.C;
 
176
            Manager::Get()->GetMacrosManager()->ReplaceMacros(tmp);
 
177
            m_Valid = wxFileExists(tmp);
 
178
            if (m_Valid)
 
179
                break;
 
180
        }
 
181
    }
 
182
    return m_Valid;
 
183
}
 
184
 
 
185
void Compiler::MakeValidID()
 
186
{
 
187
    // basically, make it XML-element compatible
 
188
    // only allow a-z, 0-9 and _
 
189
    // (it is already lowercase)
 
190
    // any non-conformant character will be removed
 
191
 
 
192
    wxString newID;
 
193
    if (m_ID.IsEmpty())
 
194
        m_ID = m_Name;
 
195
 
 
196
    size_t pos = 0;
 
197
    while (pos < m_ID.Length())
 
198
    {
 
199
        wxChar ch = m_ID[pos];
 
200
        if (wxIsalnum(ch) || ch == _T('_'))
 
201
        {
 
202
            // valid character
 
203
            newID.Append(ch);
 
204
        }
 
205
        else if (wxIsspace(ch))
 
206
        {
 
207
            // convert spaces to underscores
 
208
            newID.Append(_T('_'));
 
209
        }
 
210
        ++pos;
 
211
    }
 
212
 
 
213
    // make sure it's not starting with a number.
 
214
    // if it is, prepend "cb"
 
215
    if (wxIsdigit(newID.GetChar(0)))
 
216
        newID.Prepend(_T("cb"));
 
217
 
 
218
    if (newID.IsEmpty())
 
219
    {
 
220
        // empty? wtf?
 
221
        cbThrow(_T("Can't create a valid compiler ID for ") + m_Name);
 
222
    }
 
223
    m_ID = newID.Lower();
 
224
 
 
225
    // check for unique ID
 
226
    if (!IsUniqueID(m_ID))
 
227
        cbThrow(_T("Compiler ID already exists for ") + m_Name);
 
228
    m_CompilerIDs.Add(m_ID);
 
229
}
 
230
 
 
231
CompilerCommandGenerator* Compiler::GetCommandGenerator()
 
232
{
 
233
    return new CompilerCommandGenerator;
 
234
}
 
235
 
 
236
void Compiler::Init(cbProject* project)
 
237
{
 
238
    if (!m_pGenerator)
 
239
        m_pGenerator = GetCommandGenerator();
 
240
    m_pGenerator->Init(project);
 
241
}
 
242
 
 
243
void Compiler::GenerateCommandLine(wxString& macro,
 
244
                                    ProjectBuildTarget* target,
 
245
                                    ProjectFile* pf,
 
246
                                    const wxString& file,
 
247
                                    const wxString& object,
 
248
                                    const wxString& FlatObject,
 
249
                                    const wxString& deps)
 
250
{
 
251
    if (!m_pGenerator)
 
252
        cbThrow(_T("Compiler::Init() not called or generator invalid!"));
 
253
    m_pGenerator->GenerateCommandLine(macro, target, pf, file, object, FlatObject, deps);
 
254
}
 
255
 
 
256
const wxArrayString& Compiler::GetCompilerSearchDirs(ProjectBuildTarget* target)
 
257
{
 
258
    static wxArrayString retIfError;
 
259
    retIfError.Clear();
 
260
    if (!m_pGenerator)
 
261
        return retIfError;
 
262
 
 
263
    return m_pGenerator->GetCompilerSearchDirs(target);
 
264
}
 
265
 
 
266
const wxArrayString& Compiler::GetLinkerSearchDirs(ProjectBuildTarget* target)
 
267
{
 
268
    static wxArrayString retIfError;
 
269
    retIfError.Clear();
 
270
    if (!m_pGenerator)
 
271
        return retIfError;
 
272
 
 
273
    return m_pGenerator->GetLinkerSearchDirs(target);
 
274
}
 
275
 
 
276
const wxString& Compiler::GetCommand(CommandType ct, const wxString& fileExtension) const
 
277
{
 
278
        size_t catchAll = 0;
 
279
        const CompilerToolsVector& vec = m_Commands[ct];
 
280
        
 
281
        if (!fileExtension.IsEmpty())
 
282
        {
 
283
                for (size_t i = 0; i < vec.size(); ++i)
 
284
                {
 
285
                        if (vec[i].extensions.GetCount() == 0)
 
286
                        {
 
287
                                catchAll = i;
 
288
                                continue;
 
289
                        }
 
290
                        for (size_t n = 0; n < vec[i].extensions.GetCount(); ++n)
 
291
                        {
 
292
                                if (vec[i].extensions[n] == fileExtension)
 
293
                                {
 
294
                                        return vec[i].command;
 
295
                                }
 
296
                        }
 
297
                }
 
298
        }
 
299
        return vec[catchAll].command;
 
300
}
 
301
 
 
302
const CompilerTool& Compiler::GetCompilerTool(CommandType ct, const wxString& fileExtension) const
 
303
{
 
304
        size_t catchAll = 0;
 
305
        const CompilerToolsVector& vec = m_Commands[ct];
 
306
        
 
307
        if (!fileExtension.IsEmpty())
 
308
        {
 
309
                for (size_t i = 0; i < vec.size(); ++i)
 
310
                {
 
311
                        if (vec[i].extensions.GetCount() == 0)
 
312
                        {
 
313
                                catchAll = i;
 
314
                                continue;
 
315
                        }
 
316
                        for (size_t n = 0; n < vec[i].extensions.GetCount(); ++n)
 
317
                        {
 
318
                                if (vec[i].extensions[n] == fileExtension)
 
319
                                {
 
320
                                        return vec[i];
 
321
                                }
 
322
                        }
 
323
                }
 
324
        }
 
325
        return vec[catchAll];
 
326
}
 
327
 
 
328
void Compiler::MirrorCurrentSettings()
 
329
{
 
330
    // run just once
 
331
    if (m_Mirrored)
 
332
        return;
 
333
 
 
334
    // keep the current settings safe
 
335
    // so we can compare them when saving: this way we can only save what's
 
336
    // different from the defaults
 
337
 
 
338
    m_Mirror.Name = m_Name;
 
339
    m_Mirror.MasterPath = m_MasterPath;
 
340
    m_Mirror.ExtraPaths = m_ExtraPaths;
 
341
    for (int i = 0; i < ctCount; ++i)
 
342
        m_Mirror.Commands[i] = m_Commands[i];
 
343
    m_Mirror.Programs = m_Programs;
 
344
    m_Mirror.Switches = m_Switches;
 
345
    m_Mirror.Options = m_Options;
 
346
    m_Mirror.RegExes = m_RegExes;
 
347
 
 
348
    m_Mirror.CompilerOptions_ = m_CompilerOptions;
 
349
    m_Mirror.LinkerOptions = m_LinkerOptions;
 
350
    m_Mirror.IncludeDirs = m_IncludeDirs;
 
351
    m_Mirror.ResIncludeDirs = m_ResIncludeDirs;
 
352
    m_Mirror.LibDirs = m_LibDirs;
 
353
    m_Mirror.LinkLibs = m_LinkLibs;
 
354
    m_Mirror.CmdsBefore = m_CmdsBefore;
 
355
    m_Mirror.CmdsAfter = m_CmdsAfter;
 
356
 
 
357
    m_Mirrored = true;
 
358
}
 
359
 
 
360
void Compiler::SaveSettings(const wxString& baseKey)
 
361
{
 
362
    ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("compiler"));
 
363
 
 
364
    // save settings version
 
365
    cfg->Write(_T("settings_version"), CompilerSettingsVersion);
 
366
 
 
367
    wxString tmp;
 
368
 
 
369
    // delete old-style keys (using integer IDs)
 
370
    tmp.Printf(_T("%s/set%3.3d"), baseKey.c_str(), CompilerFactory::GetCompilerIndex(this) + 1);
 
371
    cfg->DeleteSubPath(tmp);
 
372
 
 
373
    tmp.Printf(_T("%s/%s"), baseKey.c_str(), m_ID.c_str());
 
374
 
 
375
    cfg->Write(tmp + _T("/name"), m_Name);
 
376
    cfg->Write(tmp + _T("/parent"), m_ParentID, true);
 
377
 
 
378
    if (m_Mirror.CompilerOptions_ != m_CompilerOptions)
 
379
    {
 
380
        wxString key = GetStringFromArray(m_CompilerOptions);
 
381
        cfg->Write(tmp + _T("/compiler_options"), key, false);
 
382
    }
 
383
    if (m_Mirror.LinkerOptions != m_LinkerOptions)
 
384
    {
 
385
        wxString key = GetStringFromArray(m_LinkerOptions);
 
386
        cfg->Write(tmp + _T("/linker_options"), key, false);
 
387
    }
 
388
    if (m_Mirror.IncludeDirs != m_IncludeDirs)
 
389
    {
 
390
        wxString key = GetStringFromArray(m_IncludeDirs);
 
391
        cfg->Write(tmp + _T("/include_dirs"), key, false);
 
392
    }
 
393
    if (m_Mirror.ResIncludeDirs != m_ResIncludeDirs)
 
394
    {
 
395
        wxString key = GetStringFromArray(m_ResIncludeDirs);
 
396
        cfg->Write(tmp + _T("/res_include_dirs"), key, false);
 
397
    }
 
398
    if (m_Mirror.LibDirs != m_LibDirs)
 
399
    {
 
400
        wxString key = GetStringFromArray(m_LibDirs);
 
401
        cfg->Write(tmp + _T("/library_dirs"), key, false);
 
402
    }
 
403
    if (m_Mirror.LinkLibs != m_LinkLibs)
 
404
    {
 
405
        wxString key = GetStringFromArray(m_LinkLibs);
 
406
        cfg->Write(tmp + _T("/libraries"), key, false);
 
407
    }
 
408
    if (m_Mirror.CmdsBefore != m_CmdsBefore)
 
409
    {
 
410
        wxString key = GetStringFromArray(m_CmdsBefore);
 
411
        cfg->Write(tmp + _T("/commands_before"), key, true);
 
412
    }
 
413
    if (m_Mirror.CmdsAfter != m_CmdsAfter)
 
414
    {
 
415
        wxString key = GetStringFromArray(m_CmdsAfter);
 
416
        cfg->Write(tmp + _T("/commands_after"), key, true);
 
417
    }
 
418
 
 
419
    if (m_Mirror.MasterPath != m_MasterPath)
 
420
        cfg->Write(tmp + _T("/master_path"), m_MasterPath, true);
 
421
    if (m_Mirror.ExtraPaths != m_ExtraPaths)
 
422
        cfg->Write(tmp + _T("/extra_paths"), GetStringFromArray(m_ExtraPaths, _T(";")), true);
 
423
    if (m_Mirror.Programs.C != m_Programs.C)
 
424
        cfg->Write(tmp + _T("/c_compiler"), m_Programs.C, true);
 
425
    if (m_Mirror.Programs.CPP != m_Programs.CPP)
 
426
        cfg->Write(tmp + _T("/cpp_compiler"), m_Programs.CPP, true);
 
427
    if (m_Mirror.Programs.LD != m_Programs.LD)
 
428
        cfg->Write(tmp + _T("/linker"), m_Programs.LD, true);
 
429
    if (m_Mirror.Programs.LIB != m_Programs.LIB)
 
430
        cfg->Write(tmp + _T("/lib_linker"), m_Programs.LIB, true);
 
431
    if (m_Mirror.Programs.WINDRES != m_Programs.WINDRES)
 
432
        cfg->Write(tmp + _T("/res_compiler"), m_Programs.WINDRES, true);
 
433
    if (m_Mirror.Programs.MAKE != m_Programs.MAKE)
 
434
        cfg->Write(tmp + _T("/make"), m_Programs.MAKE, true);
 
435
    if (m_Mirror.Programs.DBG != m_Programs.DBG)
 
436
        cfg->Write(tmp + _T("/debugger"), m_Programs.DBG, true);
 
437
 
 
438
    for (int i = 0; i < ctCount; ++i)
 
439
    {
 
440
        for (size_t n = 0; n < m_Commands[i].size(); ++n)
 
441
        {
 
442
                        if (n >= m_Mirror.Commands[i].size() || m_Mirror.Commands[i][n] != m_Commands[i][n])
 
443
                        {
 
444
                                wxString key = wxString::Format(_T("%s/macros/%s/tool%d/"), tmp.c_str(), CommandTypeDescriptions[i].c_str(), n);
 
445
                                cfg->Write(key + _T("command"), m_Commands[i][n].command);
 
446
                                cfg->Write(key + _T("extensions"), m_Commands[i][n].extensions);
 
447
                                cfg->Write(key + _T("generatedFiles"), m_Commands[i][n].generatedFiles);
 
448
                        }
 
449
        }
 
450
    }
 
451
 
 
452
    // switches
 
453
    if (m_Mirror.Switches.includeDirs != m_Switches.includeDirs)
 
454
        cfg->Write(tmp + _T("/switches/includes"), m_Switches.includeDirs, true);
 
455
    if (m_Mirror.Switches.libDirs != m_Switches.libDirs)
 
456
        cfg->Write(tmp + _T("/switches/libs"), m_Switches.libDirs, true);
 
457
    if (m_Mirror.Switches.linkLibs != m_Switches.linkLibs)
 
458
        cfg->Write(tmp + _T("/switches/link"), m_Switches.linkLibs, true);
 
459
    if (m_Mirror.Switches.defines != m_Switches.defines)
 
460
        cfg->Write(tmp + _T("/switches/define"), m_Switches.defines, true);
 
461
    if (m_Mirror.Switches.genericSwitch != m_Switches.genericSwitch)
 
462
        cfg->Write(tmp + _T("/switches/generic"), m_Switches.genericSwitch, true);
 
463
    if (m_Mirror.Switches.objectExtension != m_Switches.objectExtension)
 
464
        cfg->Write(tmp + _T("/switches/objectext"), m_Switches.objectExtension, true);
 
465
    if (m_Mirror.Switches.needDependencies != m_Switches.needDependencies)
 
466
        cfg->Write(tmp + _T("/switches/deps"), m_Switches.needDependencies);
 
467
    if (m_Mirror.Switches.forceCompilerUseQuotes != m_Switches.forceCompilerUseQuotes)
 
468
        cfg->Write(tmp + _T("/switches/forceCompilerQuotes"), m_Switches.forceCompilerUseQuotes);
 
469
    if (m_Mirror.Switches.forceLinkerUseQuotes != m_Switches.forceLinkerUseQuotes)
 
470
        cfg->Write(tmp + _T("/switches/forceLinkerQuotes"), m_Switches.forceLinkerUseQuotes);
 
471
    if (m_Mirror.Switches.logging != m_Switches.logging)
 
472
        cfg->Write(tmp + _T("/switches/logging"), m_Switches.logging);
 
473
    if (m_Mirror.Switches.libPrefix != m_Switches.libPrefix)
 
474
        cfg->Write(tmp + _T("/switches/libPrefix"), m_Switches.libPrefix, true);
 
475
    if (m_Mirror.Switches.libExtension != m_Switches.libExtension)
 
476
        cfg->Write(tmp + _T("/switches/libExtension"), m_Switches.libExtension, true);
 
477
    if (m_Mirror.Switches.linkerNeedsLibPrefix != m_Switches.linkerNeedsLibPrefix)
 
478
        cfg->Write(tmp + _T("/switches/linkerNeedsLibPrefix"), m_Switches.linkerNeedsLibPrefix);
 
479
    if (m_Mirror.Switches.linkerNeedsLibExtension != m_Switches.linkerNeedsLibExtension)
 
480
        cfg->Write(tmp + _T("/switches/linkerNeedsLibExtension"), m_Switches.linkerNeedsLibExtension);
 
481
    if (m_Mirror.Switches.forceFwdSlashes != m_Switches.forceFwdSlashes)
 
482
        cfg->Write(tmp + _T("/switches/forceFwdSlashes"), m_Switches.forceFwdSlashes);
 
483
    if (m_Mirror.Switches.supportsPCH != m_Switches.supportsPCH)
 
484
        cfg->Write(tmp + _T("/switches/supportsPCH"), m_Switches.supportsPCH);
 
485
    if (m_Mirror.Switches.PCHExtension != m_Switches.PCHExtension)
 
486
        cfg->Write(tmp + _T("/switches/pchExtension"), m_Switches.PCHExtension);
 
487
    if (m_Mirror.Switches.UseFlatObjects != m_Switches.UseFlatObjects)
 
488
        cfg->Write(tmp + _T("/switches/UseFlatObjects"), m_Switches.UseFlatObjects);
 
489
    if (m_Mirror.Switches.UseFullSourcePaths != m_Switches.UseFullSourcePaths)
 
490
        cfg->Write(tmp + _T("/switches/UseFullSourcePaths"), m_Switches.UseFullSourcePaths);
 
491
 
 
492
    // regexes
 
493
    cfg->DeleteSubPath(tmp + _T("/regex"));
 
494
    wxString group;
 
495
    for (size_t i = 0; i < m_RegExes.Count(); ++i)
 
496
    {
 
497
        if (i < m_Mirror.RegExes.GetCount() && m_Mirror.RegExes[i] == m_RegExes[i])
 
498
            continue;
 
499
 
 
500
        group.Printf(_T("%s/regex/re%3.3d"), tmp.c_str(), i + 1);
 
501
        RegExStruct& rs = m_RegExes[i];
 
502
        cfg->Write(group + _T("/description"), rs.desc, true);
 
503
        if (rs.lt != 0)
 
504
            cfg->Write(group + _T("/type"), rs.lt);
 
505
            cfg->Write(group + _T("/regex"), rs.regex, true);
 
506
        if (rs.msg[0] != 0)
 
507
            cfg->Write(group + _T("/msg1"), rs.msg[0]);
 
508
        if (rs.msg[1] != 0)
 
509
            cfg->Write(group + _T("/msg2"), rs.msg[1]);
 
510
        if (rs.msg[2] != 0)
 
511
            cfg->Write(group + _T("/msg3"), rs.msg[2]);
 
512
        if (rs.filename != 0)
 
513
            cfg->Write(group + _T("/filename"), rs.filename);
 
514
        if (rs.line != 0)
 
515
            cfg->Write(group + _T("/line"), rs.line);
 
516
    }
 
517
 
 
518
    // custom vars
 
519
    wxString configpath = tmp + _T("/custom_variables/");
 
520
    cfg->DeleteSubPath(configpath);
 
521
    const StringHash& v = GetAllVars();
 
522
    for (StringHash::const_iterator it = v.begin(); it != v.end(); ++it)
 
523
    {
 
524
        cfg->Write(configpath + it->first, it->second);
 
525
    }
 
526
}
 
527
 
 
528
void Compiler::LoadSettings(const wxString& baseKey)
 
529
{
 
530
    // before loading any compiler settings, keep the current settings safe
 
531
    // so we can compare them when saving: this way we can only save what's
 
532
    // different from the defaults
 
533
    MirrorCurrentSettings();
 
534
 
 
535
    ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("compiler"));
 
536
 
 
537
    // read settings version
 
538
    wxString version = cfg->Read(_T("settings_version"));
 
539
    bool versionMismatch = version != CompilerSettingsVersion;
 
540
 
 
541
    wxString tmp;
 
542
 
 
543
    // if using old-style keys (using integer IDs), notify user about the changes
 
544
    static bool saidAboutCompilerIDs = false;
 
545
    tmp.Printf(_T("%s/set%3.3d"), baseKey.c_str(), CompilerFactory::GetCompilerIndex(this) + 1);
 
546
    if (cfg->Exists(tmp + _T("/name")))
 
547
    {
 
548
        if (!saidAboutCompilerIDs)
 
549
        {
 
550
            saidAboutCompilerIDs = true;
 
551
            cbMessageBox(_("Compilers now use unique names instead of integer IDs.\n"
 
552
                            "Projects will be updated accordingly on load, mostly automatic."),
 
553
                            _("Information"),
 
554
                            wxICON_INFORMATION);
 
555
        }
 
556
        // at this point, we 'll be using the old style configuration to load settings
 
557
    }
 
558
    else // it's OK to use new style
 
559
        tmp.Printf(_T("%s/%s"), baseKey.c_str(), m_ID.c_str());
 
560
 
 
561
    if (!cfg->Exists(tmp + _T("/name")))
 
562
        return;
 
563
 
 
564
    wxString sep = wxFileName::GetPathSeparator();
 
565
 
 
566
//    if (m_ID > 255) // name changes are allowed only for user compilers
 
567
    m_Name = cfg->Read(tmp + _T("/name"), m_Name);
 
568
 
 
569
    m_MasterPath = cfg->Read(tmp + _T("/master_path"), m_MasterPath);
 
570
    m_ExtraPaths = GetArrayFromString(cfg->Read(tmp + _T("/extra_paths"), _T("")), _T(";"));
 
571
    m_Programs.C = cfg->Read(tmp + _T("/c_compiler"), m_Programs.C);
 
572
    m_Programs.CPP = cfg->Read(tmp + _T("/cpp_compiler"), m_Programs.CPP);
 
573
    m_Programs.LD = cfg->Read(tmp + _T("/linker"), m_Programs.LD);
 
574
    m_Programs.LIB = cfg->Read(tmp + _T("/lib_linker"), m_Programs.LIB);
 
575
    m_Programs.WINDRES = cfg->Read(tmp + _T("/res_compiler"), m_Programs.WINDRES);
 
576
    m_Programs.MAKE = cfg->Read(tmp + _T("/make"), m_Programs.MAKE);
 
577
    m_Programs.DBG = cfg->Read(tmp + _T("/debugger"), m_Programs.DBG);
 
578
 
 
579
    SetCompilerOptions(GetArrayFromString(cfg->Read(tmp + _T("/compiler_options"), wxEmptyString)));
 
580
    SetLinkerOptions(GetArrayFromString(cfg->Read(tmp + _T("/linker_options"), wxEmptyString)));
 
581
    SetIncludeDirs(GetArrayFromString(cfg->Read(tmp + _T("/include_dirs"), wxEmptyString)));
 
582
    SetResourceIncludeDirs(GetArrayFromString(cfg->Read(tmp + _T("/res_include_dirs"), wxEmptyString)));
 
583
    SetLibDirs(GetArrayFromString(cfg->Read(tmp + _T("/library_dirs"), wxEmptyString)));
 
584
    SetLinkLibs(GetArrayFromString(cfg->Read(tmp + _T("/libraries"), _T(""))));
 
585
    SetCommandsBeforeBuild(GetArrayFromString(cfg->Read(tmp + _T("/commands_before"), wxEmptyString)));
 
586
    SetCommandsAfterBuild(GetArrayFromString(cfg->Read(tmp + _T("/commands_after"), wxEmptyString)));
 
587
 
 
588
    for (int i = 0; i < ctCount; ++i)
 
589
    {
 
590
        wxArrayString keys = cfg->EnumerateSubPaths(tmp + _T("/macros/") + CommandTypeDescriptions[i]);
 
591
        for (size_t n = 0; n < keys.size(); ++n)
 
592
        {
 
593
                unsigned long index;
 
594
                if (keys[n].Mid(4).ToULong(&index)) // skip 'tool'
 
595
                {
 
596
                        while (index >= m_Commands[i].size())
 
597
                                        m_Commands[i].push_back(CompilerTool());
 
598
                                CompilerTool& tool = m_Commands[i][index];
 
599
                                
 
600
                                wxString key = wxString::Format(_T("%s/macros/%s/tool%d/"), tmp.c_str(), CommandTypeDescriptions[i].c_str(), index);
 
601
                                tool.command = cfg->Read(key + _T("command"));
 
602
                                tool.extensions = cfg->ReadArrayString(key + _T("extensions"));
 
603
                                tool.generatedFiles = cfg->ReadArrayString(key + _T("generatedFiles"));
 
604
                }
 
605
        }
 
606
    }
 
607
 
 
608
    // switches
 
609
    m_Switches.includeDirs = cfg->Read(tmp + _T("/switches/includes"), m_Switches.includeDirs);
 
610
    m_Switches.libDirs = cfg->Read(tmp + _T("/switches/libs"), m_Switches.libDirs);
 
611
    m_Switches.linkLibs = cfg->Read(tmp + _T("/switches/link"), m_Switches.linkLibs);
 
612
    m_Switches.defines = cfg->Read(tmp + _T("/switches/define"), m_Switches.defines);
 
613
    m_Switches.genericSwitch = cfg->Read(tmp + _T("/switches/generic"), m_Switches.genericSwitch);
 
614
    m_Switches.objectExtension = cfg->Read(tmp + _T("/switches/objectext"), m_Switches.objectExtension);
 
615
    m_Switches.needDependencies = cfg->ReadBool(tmp + _T("/switches/deps"), m_Switches.needDependencies);
 
616
    m_Switches.forceCompilerUseQuotes = cfg->ReadBool(tmp + _T("/switches/forceCompilerQuotes"), m_Switches.forceCompilerUseQuotes);
 
617
    m_Switches.forceLinkerUseQuotes = cfg->ReadBool(tmp + _T("/switches/forceLinkerQuotes"), m_Switches.forceLinkerUseQuotes);
 
618
    m_Switches.logging = (CompilerLoggingType)cfg->ReadInt(tmp + _T("/switches/logging"), m_Switches.logging);
 
619
    m_Switches.libPrefix = cfg->Read(tmp + _T("/switches/libPrefix"), m_Switches.libPrefix);
 
620
    m_Switches.libExtension = cfg->Read(tmp + _T("/switches/libExtension"), m_Switches.libExtension);
 
621
    m_Switches.linkerNeedsLibPrefix = cfg->ReadBool(tmp + _T("/switches/linkerNeedsLibPrefix"), m_Switches.linkerNeedsLibPrefix);
 
622
    m_Switches.linkerNeedsLibExtension = cfg->ReadBool(tmp + _T("/switches/linkerNeedsLibExtension"), m_Switches.linkerNeedsLibExtension);
 
623
    m_Switches.forceFwdSlashes = cfg->ReadBool(tmp + _T("/switches/forceFwdSlashes"), m_Switches.forceFwdSlashes);
 
624
    m_Switches.supportsPCH = cfg->ReadBool(tmp + _T("/switches/supportsPCH"), m_Switches.supportsPCH);
 
625
    m_Switches.PCHExtension = cfg->Read(tmp + _T("/switches/pchExtension"), m_Switches.PCHExtension);
 
626
    m_Switches.UseFlatObjects = cfg->ReadBool(tmp + _T("/switches/UseFlatObjects"), m_Switches.UseFlatObjects);
 
627
    m_Switches.UseFullSourcePaths = cfg->ReadBool(tmp + _T("/switches/UseFullSourcePaths"), m_Switches.UseFullSourcePaths);
 
628
 
 
629
    // regexes
 
630
 
 
631
    // because we 're only saving changed regexes, we can't just iterate like before.
 
632
    // instead, we must iterate all child-keys and deduce the regex index number from
 
633
    // the key name
 
634
    wxArrayString keys = cfg->EnumerateSubPaths(tmp + _T("/regex/"));
 
635
    wxString group;
 
636
    long index;
 
637
    for (size_t i = 0; i < keys.GetCount(); ++i)
 
638
    {
 
639
        wxString key = keys[i];
 
640
 
 
641
        // reNNN
 
642
        if (!key.StartsWith(_T("re")))
 
643
            continue;
 
644
        key.Remove(0, 2);
 
645
        if (!key.ToLong(&index, 10))
 
646
            continue;
 
647
 
 
648
        // 'index' now holds the regex index.
 
649
        // read everything and either assign it to an existing regex
 
650
        // if the index exists, or add a new regex
 
651
 
 
652
        group.Printf(_T("%s/regex/re%3.3d"), tmp.c_str(), index);
 
653
        if (!cfg->Exists(group+_T("/description")))
 
654
            continue;
 
655
 
 
656
        RegExStruct rs;
 
657
        rs.desc = cfg->Read(group + _T("/description"));
 
658
        rs.lt = (CompilerLineType)cfg->ReadInt(group + _T("/type"), 0);
 
659
        rs.regex = cfg->Read(group + _T("/regex"));
 
660
        rs.msg[0] = cfg->ReadInt(group + _T("/msg1"), 0);
 
661
        rs.msg[1] = cfg->ReadInt(group + _T("/msg2"), 0);
 
662
        rs.msg[2] = cfg->ReadInt(group + _T("/msg3"), 0);
 
663
        rs.filename = cfg->ReadInt(group + _T("/filename"), 0);
 
664
        rs.line = cfg->ReadInt(group + _T("/line"), 0);
 
665
 
 
666
        if (index <= (long)m_RegExes.GetCount())
 
667
            m_RegExes[index - 1] = rs;
 
668
        else
 
669
            m_RegExes.Add(rs);
 
670
    }
 
671
 
 
672
    // custom vars
 
673
    wxString configpath = tmp + _T("/custom_variables/");
 
674
    UnsetAllVars();
 
675
    wxArrayString list = cfg->EnumerateKeys(configpath);
 
676
    for (unsigned int i = 0; i < list.GetCount(); ++i)
 
677
        SetVar(list[i], cfg->Read(configpath + _T('/') + list[i]), false);
 
678
 
 
679
    if (versionMismatch)
 
680
    {
 
681
        wxString msg;
 
682
        msg << _("Some compiler settings defaults have changed in this version.\n"
 
683
                "It is recommended that you allow updating of your settings to "
 
684
                "the new defaults.\n"
 
685
                "Only disallow this if you don't want to lose any customizations "
 
686
                "you have done to this compiler's settings.\n\n"
 
687
                "Note that the only settings that are affected are those found in "
 
688
                "\"Advanced compiler options\"...\n\n"
 
689
                "Do you want to update your current settings to the new defaults?");
 
690
        // don't ask if the compiler is not valid (i.e. not installed), just update
 
691
        if (!IsValid() || cbMessageBox(msg, m_Name, wxICON_QUESTION | wxYES_NO) == wxID_YES)
 
692
        {
 
693
            for (int i = 0; i < ctCount; ++i)
 
694
                m_Commands[i] = m_Mirror.Commands[i];
 
695
            m_Switches = m_Mirror.Switches;
 
696
            m_Options = m_Mirror.Options;
 
697
            m_RegExes = m_Mirror.RegExes;
 
698
        }
 
699
    }
 
700
}
 
701
 
 
702
CompilerLineType Compiler::CheckForWarningsAndErrors(const wxString& line)
 
703
{
 
704
    m_ErrorFilename.Clear();
 
705
    m_ErrorLine.Clear();
 
706
    m_Error.Clear();
 
707
 
 
708
    for (size_t i = 0; i < m_RegExes.Count(); ++i)
 
709
    {
 
710
        RegExStruct& rs = m_RegExes[i];
 
711
        if (rs.regex.IsEmpty())
 
712
            continue;
 
713
        wxRegEx regex(rs.regex);
 
714
        if (regex.Matches(line))
 
715
        {
 
716
            if (rs.filename > 0)
 
717
                 m_ErrorFilename = UnixFilename(regex.GetMatch(line, rs.filename));
 
718
            if (rs.line > 0)
 
719
                m_ErrorLine = regex.GetMatch(line, rs.line);
 
720
            for (int x = 0; x < 3; ++x)
 
721
            {
 
722
                if (rs.msg[x] > 0)
 
723
                {
 
724
                    if (!m_Error.IsEmpty())
 
725
                        m_Error << _T(" ");
 
726
                    m_Error << regex.GetMatch(line, rs.msg[x]);
 
727
                }
 
728
            }
 
729
            return rs.lt;
 
730
        }
 
731
    }
 
732
    return cltNormal; // default return value
 
733
}