~ubuntu-branches/ubuntu/oneiric/codeblocks/oneiric

« back to all changes in this revision

Viewing changes to src/sdk/projectloader.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: projectloader.cpp 4909 2008-02-27 13:15:26Z mortenmacfly $
 
7
 * $HeadURL: svn://svn.berlios.de/codeblocks/tags/8.02/src/sdk/projectloader.cpp $
 
8
 */
 
9
 
 
10
#include "sdk_precomp.h"
 
11
 
 
12
#ifndef CB_PRECOMP
 
13
    #include <wx/confbase.h>
 
14
    #include <wx/fileconf.h>
 
15
    #include <wx/intl.h>
 
16
    #include <wx/filename.h>
 
17
    #include <wx/msgdlg.h>
 
18
    #include <wx/stopwatch.h>
 
19
    #include "manager.h"
 
20
    #include "configmanager.h"
 
21
    #include "projectmanager.h"
 
22
    #include "logmanager.h"
 
23
    #include "macrosmanager.h"
 
24
    #include "cbproject.h"
 
25
    #include "compilerfactory.h"
 
26
    #include "globals.h"
 
27
#endif
 
28
 
 
29
#include "filefilters.h"
 
30
#include "projectloader.h"
 
31
#include "projectloader_hooks.h"
 
32
#include "annoyingdialog.h"
 
33
#include "configmanager.h"
 
34
#include "tinyxml/tinywxuni.h"
 
35
 
 
36
ProjectLoader::ProjectLoader(cbProject* project)
 
37
    : m_pProject(project),
 
38
    m_Upgraded(false),
 
39
    m_OpenDirty(false),
 
40
    m_1_4_to_1_5_deftarget(-1),
 
41
    m_IsPre_1_6(false)
 
42
{
 
43
    //ctor
 
44
}
 
45
 
 
46
ProjectLoader::~ProjectLoader()
 
47
{
 
48
    //dtor
 
49
}
 
50
 
 
51
bool ProjectLoader::Open(const wxString& filename)
 
52
{
 
53
    return Open(filename, 0);
 
54
}
 
55
 
 
56
bool ProjectLoader::Open(const wxString& filename, TiXmlElement** ppExtensions)
 
57
{
 
58
    LogManager* pMsg = Manager::Get()->GetLogManager();
 
59
    if (!pMsg)
 
60
        return false;
 
61
 
 
62
    wxStopWatch sw;
 
63
    pMsg->DebugLog(_T("Loading project file..."));
 
64
    TiXmlDocument doc;
 
65
    if (!TinyXML::LoadDocument(filename, &doc))
 
66
        return false;
 
67
 
 
68
    pMsg->DebugLog(_T("Parsing project file..."));
 
69
    TiXmlElement* root;
 
70
    TiXmlElement* proj;
 
71
 
 
72
    root = doc.FirstChildElement("CodeBlocks_project_file");
 
73
    if (!root)
 
74
    {
 
75
        // old tag
 
76
        root = doc.FirstChildElement("Code::Blocks_project_file");
 
77
        if (!root)
 
78
        {
 
79
            pMsg->DebugLog(_T("Not a valid Code::Blocks project file..."));
 
80
            return false;
 
81
        }
 
82
    }
 
83
    proj = root->FirstChildElement("Project");
 
84
    if (!proj)
 
85
    {
 
86
        pMsg->DebugLog(_T("No 'Project' element in file..."));
 
87
        return false;
 
88
    }
 
89
 
 
90
    m_IsPre_1_2 = false; // flag for some changed defaults in version 1.2
 
91
    TiXmlElement* version = root->FirstChildElement("FileVersion");
 
92
    // don't show messages if we 're running a batch build (i.e. no gui)
 
93
    if (!Manager::IsBatchBuild() && version)
 
94
    {
 
95
        int major = PROJECT_FILE_VERSION_MAJOR;
 
96
        int minor = PROJECT_FILE_VERSION_MINOR;
 
97
        version->QueryIntAttribute("major", &major);
 
98
        version->QueryIntAttribute("minor", &minor);
 
99
 
 
100
        m_IsPre_1_6 = major < 1 || (major == 1 && minor < 6);
 
101
 
 
102
        if (major < 1 ||
 
103
            (major == 1 && minor < 2))
 
104
        {
 
105
            // pre-1.2
 
106
            pMsg->DebugLog(F(_T("Project version is %d.%d. Defaults have changed since then..."), major, minor));
 
107
            m_IsPre_1_2 = true;
 
108
        }
 
109
        else if (major >= PROJECT_FILE_VERSION_MAJOR && minor > PROJECT_FILE_VERSION_MINOR)
 
110
        {
 
111
            pMsg->DebugLog(F(_T("Project version is > %d.%d. Trying to load..."), PROJECT_FILE_VERSION_MAJOR, PROJECT_FILE_VERSION_MINOR));
 
112
            AnnoyingDialog dlg(_("Project file format is newer/unknown"),
 
113
                                _("This project file was saved with a newer version of Code::Blocks.\n"
 
114
                                "Will try to load, but you should make sure all the settings were loaded correctly..."),
 
115
                                wxART_WARNING,
 
116
                                AnnoyingDialog::OK,
 
117
                                wxID_OK);
 
118
            dlg.ShowModal();
 
119
        }
 
120
        else
 
121
        {
 
122
            // use one message for all changes
 
123
            wxString msg;
 
124
            wxString warn_msg;
 
125
 
 
126
            // 1.5 -> 1.6: values matching defaults are not written to <Unit> sections
 
127
            if (major == 1 && minor == 5)
 
128
            {
 
129
                msg << _("1.5 to 1.6:\n");
 
130
                msg << _("  * only saves values that differ from defaults (i.e. project files are smaller now).\n");
 
131
                msg << _("  * added object names generation mode setting (normal/extended).\n");
 
132
                msg << _("  * added project notes.\n");
 
133
                msg << _("\n");
 
134
 
 
135
                warn_msg << _("* Project file updated to version 1.6:\n");
 
136
                warn_msg << _("   When a project file is saved as version 1.6, it will NO LONGER be read correctly\n");
 
137
                warn_msg << _("   by earlier Code::Blocks versions!\n");
 
138
                warn_msg << _("   So, if you plan on using this project with an earlier Code::Blocks version, you\n");
 
139
                warn_msg << _("   should probably NOT save this project as version 1.6...\n");
 
140
                warn_msg << _("\n");
 
141
            }
 
142
 
 
143
            // 1.4 -> 1.5: updated custom build command per-project file
 
144
            if (major == 1 && minor == 4)
 
145
            {
 
146
                msg << _("1.4 to 1.5:\n");
 
147
                msg << _("  * added virtual build targets.\n");
 
148
                msg << _("\n");
 
149
            }
 
150
 
 
151
            // 1.3 -> 1.4: updated custom build command per-project file
 
152
            if (major == 1 && minor == 3)
 
153
            {
 
154
                msg << _("1.3 to 1.4:\n");
 
155
                msg << _("  * changed the way custom file build commands are stored (no auto-conversion).\n");
 
156
                msg << _("\n");
 
157
            }
 
158
 
 
159
            if (!msg.IsEmpty())
 
160
            {
 
161
                m_Upgraded = true;
 
162
                msg.Prepend(wxString::Format(_("Project file format is older (%d.%d) than the current format (%d.%d).\n"
 
163
                                                "The file will automatically be upgraded on save.\n"
 
164
                                                "But please read the following list of changes, as some of them "
 
165
                                                "might not automatically convert existing (old) settings.\n"
 
166
                                                "If you don't understand what a change means, you probably don't "
 
167
                                                "use that feature so you don't have to worry about it.\n\n"
 
168
                                                "List of changes:\n"),
 
169
                                            major,
 
170
                                            minor,
 
171
                                            PROJECT_FILE_VERSION_MAJOR,
 
172
                                            PROJECT_FILE_VERSION_MINOR));
 
173
                AnnoyingDialog dlg(_("Project file format changed"),
 
174
                                    msg,
 
175
                                    wxART_INFORMATION,
 
176
                                    AnnoyingDialog::OK,
 
177
                                    wxID_OK);
 
178
                dlg.ShowModal();
 
179
            }
 
180
 
 
181
            if (!warn_msg.IsEmpty())
 
182
            {
 
183
                warn_msg.Prepend(_("!!! WARNING !!!\n\n"));
 
184
                AnnoyingDialog dlg(_("Project file upgrade warning"),
 
185
                                    warn_msg,
 
186
                                    wxART_WARNING,
 
187
                                    AnnoyingDialog::OK,
 
188
                                    wxID_OK);
 
189
                dlg.ShowModal();
 
190
            }
 
191
        }
 
192
    }
 
193
 
 
194
    DoProjectOptions(proj);
 
195
    DoBuild(proj);
 
196
    DoCompilerOptions(proj);
 
197
    DoResourceCompilerOptions(proj);
 
198
    DoLinkerOptions(proj);
 
199
    DoIncludesOptions(proj);
 
200
    DoLibsOptions(proj);
 
201
    DoExtraCommands(proj);
 
202
    DoUnits(proj);
 
203
 
 
204
    // if targets still use the "build with all" flag,
 
205
    // it's time for conversion
 
206
    if (!m_pProject->HasVirtualBuildTarget(_T("All")))
 
207
    {
 
208
        wxArrayString all;
 
209
        for (int i = 0; i < m_pProject->GetBuildTargetsCount(); ++i)
 
210
        {
 
211
            ProjectBuildTarget* bt = m_pProject->GetBuildTarget(i);
 
212
            if (bt && bt->GetIncludeInTargetAll())
 
213
                all.Add(bt->GetTitle());
 
214
        }
 
215
        if (all.GetCount())
 
216
        {
 
217
            m_pProject->DefineVirtualBuildTarget(_T("All"), all);
 
218
            m_Upgraded = true;
 
219
        }
 
220
    }
 
221
 
 
222
    // convert old deftarget int to string
 
223
    if (m_1_4_to_1_5_deftarget != -1)
 
224
    {
 
225
        ProjectBuildTarget* bt = m_pProject->GetBuildTarget(m_1_4_to_1_5_deftarget);
 
226
        if (bt)
 
227
            m_pProject->SetDefaultExecuteTarget(bt->GetTitle());
 
228
    }
 
229
 
 
230
    if (ppExtensions)
 
231
        *ppExtensions = 0;
 
232
 
 
233
    // as a last step, run all hooked callbacks
 
234
    TiXmlElement* node = proj->FirstChildElement("Extensions");
 
235
    if (node)
 
236
    {
 
237
        if (ppExtensions)
 
238
            *ppExtensions = new TiXmlElement(*node);
 
239
        ProjectLoaderHooks::CallHooks(m_pProject, node, true);
 
240
    }
 
241
 
 
242
    if (!version)
 
243
    {
 
244
        // pre 1.1 version
 
245
        ConvertVersion_Pre_1_1();
 
246
        // format changed also:
 
247
        // removed <IncludeDirs> and <LibDirs> elements and added them as child elements
 
248
        // in <Compiler> and <Linker> elements respectively
 
249
        // so set m_Upgraded to true, irrespectively of libs detection...
 
250
        m_Upgraded = true;
 
251
    }
 
252
    else
 
253
    {
 
254
        // do something important based on version
 
255
//        wxString major = version->Attribute("major");
 
256
//        wxString minor = version->Attribute("minor");
 
257
    }
 
258
 
 
259
    pMsg->DebugLog(wxString(_T("Done loading project in ")) << wxString::Format(_T("%d"), (int) sw.Time()) << _T("ms"));
 
260
    return true;
 
261
}
 
262
 
 
263
void ProjectLoader::ConvertVersion_Pre_1_1()
 
264
{
 
265
    // ask to detect linker libraries and move them to the new
 
266
    // CompileOptionsBase linker libs container
 
267
    wxString msg;
 
268
    msg.Printf(_("Project \"%s\" was saved with an earlier version of Code::Blocks.\n"
 
269
                "In the current version, link libraries are treated separately from linker options.\n"
 
270
                "Do you want to auto-detect the libraries \"%s\" is using and configure it accordingly?"),
 
271
                m_pProject->GetTitle().c_str(),
 
272
                m_pProject->GetTitle().c_str());
 
273
    if (cbMessageBox(msg, _("Question"), wxICON_QUESTION | wxYES_NO) == wxID_YES)
 
274
    {
 
275
        // project first
 
276
        ConvertLibraries(m_pProject);
 
277
 
 
278
        for (int i = 0; i < m_pProject->GetBuildTargetsCount(); ++i)
 
279
        {
 
280
            ConvertLibraries(m_pProject->GetBuildTarget(i));
 
281
            m_Upgraded = true;
 
282
        }
 
283
    }
 
284
}
 
285
 
 
286
void ProjectLoader::ConvertLibraries(CompileTargetBase* object)
 
287
{
 
288
    wxArrayString linkerOpts = object->GetLinkerOptions();
 
289
    wxArrayString linkLibs = object->GetLinkLibs();
 
290
 
 
291
    wxString compilerId = object->GetCompilerID();
 
292
    Compiler* compiler = CompilerFactory::GetCompiler(compilerId);
 
293
    wxString linkLib = compiler->GetSwitches().linkLibs;
 
294
    wxString libExt = compiler->GetSwitches().libExtension;
 
295
    size_t libExtLen = libExt.Length();
 
296
 
 
297
    size_t i = 0;
 
298
    while (i < linkerOpts.GetCount())
 
299
    {
 
300
        wxString opt = linkerOpts[i];
 
301
        if (!linkLib.IsEmpty() && opt.StartsWith(linkLib))
 
302
        {
 
303
            opt.Remove(0, 2);
 
304
            wxString ext = compiler->GetSwitches().libExtension;
 
305
            if (!ext.IsEmpty())
 
306
                ext = _T(".") + ext;
 
307
            linkLibs.Add(compiler->GetSwitches().libPrefix + opt + ext);
 
308
            linkerOpts.RemoveAt(i, 1);
 
309
        }
 
310
        else if (opt.Length() > libExtLen && opt.Right(libExtLen) == libExt)
 
311
        {
 
312
            linkLibs.Add(opt);
 
313
            linkerOpts.RemoveAt(i, 1);
 
314
        }
 
315
        else
 
316
            ++i;
 
317
    }
 
318
 
 
319
    object->SetLinkerOptions(linkerOpts);
 
320
    object->SetLinkLibs(linkLibs);
 
321
}
 
322
 
 
323
void ProjectLoader::DoMakeCommands(TiXmlElement* parentNode, CompileTargetBase* target)
 
324
{
 
325
    if (!parentNode)
 
326
        return; // no options
 
327
 
 
328
    TiXmlElement* node;
 
329
 
 
330
    node = parentNode->FirstChildElement("Build");
 
331
    if (node && node->Attribute("command"))
 
332
        target->SetMakeCommandFor(mcBuild, cbC2U(node->Attribute("command")));
 
333
 
 
334
    node = parentNode->FirstChildElement("CompileFile");
 
335
    if (node && node->Attribute("command"))
 
336
        target->SetMakeCommandFor(mcCompileFile, cbC2U(node->Attribute("command")));
 
337
 
 
338
    node = parentNode->FirstChildElement("Clean");
 
339
    if (node && node->Attribute("command"))
 
340
        target->SetMakeCommandFor(mcClean, cbC2U(node->Attribute("command")));
 
341
 
 
342
    node = parentNode->FirstChildElement("DistClean");
 
343
    if (node && node->Attribute("command"))
 
344
        target->SetMakeCommandFor(mcDistClean, cbC2U(node->Attribute("command")));
 
345
}
 
346
 
 
347
void ProjectLoader::DoVirtualTargets(TiXmlElement* parentNode)
 
348
{
 
349
    if (!parentNode)
 
350
        return;
 
351
 
 
352
    TiXmlElement* node = parentNode->FirstChildElement("Add");
 
353
    if (!node)
 
354
        return; // no virtual targets
 
355
 
 
356
    while (node)
 
357
    {
 
358
        if (node->Attribute("alias") && node->Attribute("targets"))
 
359
        {
 
360
            wxString alias = cbC2U(node->Attribute("alias"));
 
361
            wxString targets = cbC2U(node->Attribute("targets"));
 
362
            wxArrayString arr = GetArrayFromString(targets, _T(";"), true);
 
363
 
 
364
            m_pProject->DefineVirtualBuildTarget(alias, arr);
 
365
        }
 
366
 
 
367
        node = node->NextSiblingElement("Add");
 
368
    }
 
369
}
 
370
 
 
371
void ProjectLoader::DoProjectOptions(TiXmlElement* parentNode)
 
372
{
 
373
    TiXmlElement* node = parentNode->FirstChildElement("Option");
 
374
    if (!node)
 
375
        return; // no options
 
376
 
 
377
    wxString title;
 
378
    wxString makefile;
 
379
    bool makefile_custom = false;
 
380
    wxString defaultTarget;
 
381
    wxString compilerId = _T("gcc");
 
382
    bool extendedObjectNames = false;
 
383
    wxArrayString vfolders;
 
384
    int platformsFinal = spAll;
 
385
    PCHMode pch_mode = m_IsPre_1_2 ? pchSourceDir : pchObjectDir;
 
386
    bool showNotes = false;
 
387
    wxString notes;
 
388
 
 
389
    // loop through all options
 
390
    while (node)
 
391
    {
 
392
        if (node->Attribute("title"))
 
393
        {
 
394
            title = cbC2U(node->Attribute("title"));
 
395
            if (title.Trim().IsEmpty())
 
396
                title = _T("untitled");
 
397
        }
 
398
 
 
399
        else if (node->Attribute("platforms"))
 
400
            platformsFinal = GetPlatformsFromString(cbC2U(node->Attribute("platforms")));
 
401
 
 
402
        else if (node->Attribute("makefile")) // there is only one attribute per option, so "else" is a safe optimisation
 
403
            makefile = cbC2U(node->Attribute("makefile"));
 
404
 
 
405
        else if (node->Attribute("makefile_is_custom"))
 
406
            makefile_custom = strncmp(node->Attribute("makefile_is_custom"), "1", 1) == 0;
 
407
 
 
408
        // old default_target (int) node
 
409
        else if (node->QueryIntAttribute("default_target", &m_1_4_to_1_5_deftarget) == TIXML_SUCCESS)
 
410
        {
 
411
            // we read the value
 
412
        }
 
413
 
 
414
        else if (node->Attribute("default_target"))
 
415
            defaultTarget = cbC2U(node->Attribute("default_target"));
 
416
 
 
417
        else if (node->Attribute("compiler"))
 
418
            compilerId = GetValidCompilerID(cbC2U(node->Attribute("compiler")), _T("the project"));
 
419
 
 
420
        else if (node->Attribute("extended_obj_names"))
 
421
            extendedObjectNames = strncmp(node->Attribute("extended_obj_names"), "1", 1) == 0;
 
422
 
 
423
        else if (node->Attribute("pch_mode"))
 
424
            pch_mode = (PCHMode)atoi(node->Attribute("pch_mode"));
 
425
 
 
426
        else if (node->Attribute("virtualFolders"))
 
427
            vfolders = GetArrayFromString(cbC2U(node->Attribute("virtualFolders")), _T(";"));
 
428
 
 
429
        else if (node->Attribute("show_notes"))
 
430
        {
 
431
            TiXmlHandle parentHandle(node);
 
432
            TiXmlText* t = (TiXmlText *) parentHandle.FirstChild("notes").FirstChild().Node();
 
433
            if (t)
 
434
                notes = cbC2U(t->Value());
 
435
            showNotes = !notes.IsEmpty() && strncmp(node->Attribute("show_notes"), "1", 1) == 0;
 
436
        }
 
437
 
 
438
        node = node->NextSiblingElement("Option");
 
439
    }
 
440
 
 
441
    m_pProject->SetTitle(title);
 
442
    m_pProject->SetPlatforms(platformsFinal);
 
443
    m_pProject->SetMakefile(makefile);
 
444
    m_pProject->SetMakefileCustom(makefile_custom);
 
445
    m_pProject->SetDefaultExecuteTarget(defaultTarget);
 
446
    m_pProject->SetCompilerID(compilerId);
 
447
    m_pProject->SetExtendedObjectNamesGeneration(extendedObjectNames);
 
448
    m_pProject->SetModeForPCH(pch_mode);
 
449
    m_pProject->SetVirtualFolders(vfolders);
 
450
    m_pProject->SetNotes(notes);
 
451
    m_pProject->SetShowNotesOnLoad(showNotes);
 
452
 
 
453
    DoMakeCommands(parentNode->FirstChildElement("MakeCommands"), m_pProject);
 
454
    DoVirtualTargets(parentNode->FirstChildElement("VirtualTargets"));
 
455
}
 
456
 
 
457
void ProjectLoader::DoBuild(TiXmlElement* parentNode)
 
458
{
 
459
    TiXmlElement* node = parentNode->FirstChildElement("Build");
 
460
    while (node)
 
461
    {
 
462
        TiXmlElement* opt = node->FirstChildElement("Script");
 
463
        while (opt)
 
464
        {
 
465
            if (opt->Attribute("file"))
 
466
                m_pProject->AddBuildScript(cbC2U(opt->Attribute("file")));
 
467
 
 
468
            opt = opt->NextSiblingElement("Script");
 
469
        }
 
470
 
 
471
        DoBuildTarget(node);
 
472
        DoEnvironment(node, m_pProject);
 
473
        node = node->NextSiblingElement("Build");
 
474
    }
 
475
}
 
476
 
 
477
void ProjectLoader::DoBuildTarget(TiXmlElement* parentNode)
 
478
{
 
479
    TiXmlElement* node = parentNode->FirstChildElement("Target");
 
480
    if (!node)
 
481
        return; // no options
 
482
 
 
483
    while (node)
 
484
    {
 
485
        ProjectBuildTarget* target = 0L;
 
486
        wxString title = cbC2U(node->Attribute("title"));
 
487
        if (!title.IsEmpty())
 
488
            target = m_pProject->AddBuildTarget(title);
 
489
 
 
490
        if (target)
 
491
        {
 
492
            Manager::Get()->GetLogManager()->DebugLog(_T("Loading target ") + title);
 
493
            DoBuildTargetOptions(node, target);
 
494
            DoCompilerOptions(node, target);
 
495
            DoResourceCompilerOptions(node, target);
 
496
            DoLinkerOptions(node, target);
 
497
            DoIncludesOptions(node, target);
 
498
            DoLibsOptions(node, target);
 
499
            DoExtraCommands(node, target);
 
500
            DoEnvironment(node, target);
 
501
        }
 
502
 
 
503
        node = node->NextSiblingElement("Target");
 
504
    }
 
505
}
 
506
 
 
507
void ProjectLoader::DoBuildTargetOptions(TiXmlElement* parentNode, ProjectBuildTarget* target)
 
508
{
 
509
    TiXmlElement* node = parentNode->FirstChildElement("Option");
 
510
    if (!node)
 
511
        return; // no options
 
512
 
 
513
    bool use_console_runner = true;
 
514
    wxString output;
 
515
    wxString working_dir;
 
516
    wxString obj_output;
 
517
    wxString deps_output;
 
518
    wxString deps;
 
519
    wxString added;
 
520
    int type = -1;
 
521
    int platformsFinal = spAll;
 
522
    wxString compilerId = m_pProject->GetCompilerID();
 
523
    wxString parameters;
 
524
    wxString hostApplication;
 
525
    bool includeInTargetAll = m_IsPre_1_2 ? true : false;
 
526
    bool createStaticLib = false;
 
527
    bool createDefFile = false;
 
528
    int projectCompilerOptionsRelation = 3;
 
529
    int projectLinkerOptionsRelation = 3;
 
530
    int projectIncludeDirsRelation = 3;
 
531
    int projectLibDirsRelation = 3;
 
532
    int projectResIncludeDirsRelation = 3;
 
533
    TargetFilenameGenerationPolicy prefixPolicy = tgfpNone; // tgfpNone for compat. with older projects
 
534
    TargetFilenameGenerationPolicy extensionPolicy = tgfpNone;
 
535
 
 
536
    while (node)
 
537
    {
 
538
        if (node->Attribute("platforms"))
 
539
            platformsFinal = GetPlatformsFromString(cbC2U(node->Attribute("platforms")));
 
540
 
 
541
        if (node->Attribute("use_console_runner"))
 
542
            use_console_runner = strncmp(node->Attribute("use_console_runner"), "0", 1) != 0;
 
543
 
 
544
        if (node->Attribute("output"))
 
545
            output = UnixFilename(cbC2U(node->Attribute("output")));
 
546
 
 
547
        if (node->Attribute("prefix_auto"))
 
548
            prefixPolicy = atoi(node->Attribute("prefix_auto")) == 1 ? tgfpPlatformDefault : tgfpNone;
 
549
 
 
550
        if (node->Attribute("extension_auto"))
 
551
            extensionPolicy = atoi(node->Attribute("extension_auto")) == 1 ? tgfpPlatformDefault : tgfpNone;
 
552
 
 
553
        if (node->Attribute("working_dir"))
 
554
            working_dir = UnixFilename(cbC2U(node->Attribute("working_dir")));
 
555
 
 
556
        if (node->Attribute("object_output"))
 
557
            obj_output = UnixFilename(cbC2U(node->Attribute("object_output")));
 
558
 
 
559
        if (node->Attribute("deps_output"))
 
560
            deps_output = UnixFilename(cbC2U(node->Attribute("deps_output")));
 
561
 
 
562
        if (node->Attribute("external_deps"))
 
563
            deps = UnixFilename(cbC2U(node->Attribute("external_deps")));
 
564
 
 
565
        if (node->Attribute("additional_output"))
 
566
            added = UnixFilename(cbC2U(node->Attribute("additional_output")));
 
567
 
 
568
        if (node->Attribute("type"))
 
569
            type = atoi(node->Attribute("type"));
 
570
 
 
571
        if (node->Attribute("compiler"))
 
572
            compilerId = GetValidCompilerID(cbC2U(node->Attribute("compiler")), target->GetTitle());
 
573
 
 
574
        if (node->Attribute("parameters"))
 
575
            parameters = cbC2U(node->Attribute("parameters"));
 
576
 
 
577
        if (node->Attribute("host_application"))
 
578
            hostApplication = UnixFilename(cbC2U(node->Attribute("host_application")));
 
579
 
 
580
        // used in versions prior to 1.5
 
581
        if (node->Attribute("includeInTargetAll"))
 
582
            includeInTargetAll = atoi(node->Attribute("includeInTargetAll")) != 0;
 
583
 
 
584
        if (node->Attribute("createDefFile"))
 
585
            createDefFile = atoi(node->Attribute("createDefFile")) != 0;
 
586
 
 
587
        if (node->Attribute("createStaticLib"))
 
588
            createStaticLib = atoi(node->Attribute("createStaticLib")) != 0;
 
589
 
 
590
        if (node->Attribute("projectCompilerOptionsRelation"))
 
591
            projectCompilerOptionsRelation = atoi(node->Attribute("projectCompilerOptionsRelation"));
 
592
 
 
593
        if (node->Attribute("projectLinkerOptionsRelation"))
 
594
            projectLinkerOptionsRelation = atoi(node->Attribute("projectLinkerOptionsRelation"));
 
595
 
 
596
        if (node->Attribute("projectIncludeDirsRelation"))
 
597
            projectIncludeDirsRelation = atoi(node->Attribute("projectIncludeDirsRelation"));
 
598
 
 
599
        if (node->Attribute("projectLibDirsRelation"))
 
600
            projectLibDirsRelation = atoi(node->Attribute("projectLibDirsRelation"));
 
601
 
 
602
        if (node->Attribute("projectResourceIncludeDirsRelation"))
 
603
        {
 
604
            projectResIncludeDirsRelation = atoi(node->Attribute("projectResourceIncludeDirsRelation"));
 
605
            // there used to be a bug in this setting and it might have a negative or very big number
 
606
            // detect this case and set as default
 
607
            if (projectResIncludeDirsRelation < 0 || projectResIncludeDirsRelation >= ortLast)
 
608
                projectResIncludeDirsRelation = 3;
 
609
        }
 
610
 
 
611
        node = node->NextSiblingElement("Option");
 
612
    }
 
613
 
 
614
    node = parentNode->FirstChildElement("Script");
 
615
    while (node)
 
616
    {
 
617
        if (node->Attribute("file"))
 
618
            target->AddBuildScript(cbC2U(node->Attribute("file")));
 
619
 
 
620
        node = node->NextSiblingElement("Script");
 
621
    }
 
622
 
 
623
    if (type != -1)
 
624
    {
 
625
        target->SetPlatforms(platformsFinal);
 
626
        target->SetCompilerID(compilerId);
 
627
        target->SetTargetFilenameGenerationPolicy(prefixPolicy, extensionPolicy);
 
628
        target->SetTargetType((TargetType)type); // type *must* come before output filename!
 
629
        target->SetOutputFilename(output); // because if no filename defined, one will be suggested based on target type...
 
630
        target->SetUseConsoleRunner(use_console_runner);
 
631
        if (!working_dir.IsEmpty())
 
632
            target->SetWorkingDir(working_dir);
 
633
        if (!obj_output.IsEmpty())
 
634
            target->SetObjectOutput(obj_output);
 
635
        if (!deps_output.IsEmpty())
 
636
            target->SetDepsOutput(deps_output);
 
637
        target->SetExternalDeps(deps);
 
638
        target->SetAdditionalOutputFiles(added);
 
639
        target->SetExecutionParameters(parameters);
 
640
        target->SetHostApplication(hostApplication);
 
641
        target->SetIncludeInTargetAll(includeInTargetAll); // used in versions prior to 1.5
 
642
        target->SetCreateDefFile(createDefFile);
 
643
        target->SetCreateStaticLib(createStaticLib);
 
644
        target->SetOptionRelation(ortCompilerOptions, (OptionsRelation)projectCompilerOptionsRelation);
 
645
        target->SetOptionRelation(ortLinkerOptions, (OptionsRelation)projectLinkerOptionsRelation);
 
646
        target->SetOptionRelation(ortIncludeDirs, (OptionsRelation)projectIncludeDirsRelation);
 
647
        target->SetOptionRelation(ortLibDirs, (OptionsRelation)projectLibDirsRelation);
 
648
        target->SetOptionRelation(ortResDirs, (OptionsRelation)projectResIncludeDirsRelation);
 
649
 
 
650
        DoMakeCommands(parentNode->FirstChildElement("MakeCommands"), target);
 
651
    }
 
652
}
 
653
 
 
654
void ProjectLoader::DoCompilerOptions(TiXmlElement* parentNode, ProjectBuildTarget* target)
 
655
{
 
656
    TiXmlElement* node = parentNode->FirstChildElement("Compiler");
 
657
    if (!node)
 
658
        return; // no options
 
659
 
 
660
    TiXmlElement* child = node->FirstChildElement("Add");
 
661
    while (child)
 
662
    {
 
663
        wxString option = cbC2U(child->Attribute("option"));
 
664
        wxString dir = cbC2U(child->Attribute("directory"));
 
665
        if (!option.IsEmpty())
 
666
        {
 
667
            if (target)
 
668
                target->AddCompilerOption(option);
 
669
            else
 
670
                m_pProject->AddCompilerOption(option);
 
671
        }
 
672
        if (!dir.IsEmpty())
 
673
        {
 
674
            if (target)
 
675
                target->AddIncludeDir(dir);
 
676
            else
 
677
                m_pProject->AddIncludeDir(dir);
 
678
        }
 
679
 
 
680
        child = child->NextSiblingElement("Add");
 
681
    }
 
682
}
 
683
 
 
684
void ProjectLoader::DoResourceCompilerOptions(TiXmlElement* parentNode, ProjectBuildTarget* target)
 
685
{
 
686
    TiXmlElement* node = parentNode->FirstChildElement("ResourceCompiler");
 
687
    if (!node)
 
688
        return; // no options
 
689
 
 
690
    TiXmlElement* child = node->FirstChildElement("Add");
 
691
    while (child)
 
692
    {
 
693
        wxString dir = cbC2U(child->Attribute("directory"));
 
694
        if (!dir.IsEmpty())
 
695
        {
 
696
            if (target)
 
697
                target->AddResourceIncludeDir(dir);
 
698
            else
 
699
                m_pProject->AddResourceIncludeDir(dir);
 
700
        }
 
701
 
 
702
        child = child->NextSiblingElement("Add");
 
703
    }
 
704
}
 
705
 
 
706
void ProjectLoader::DoLinkerOptions(TiXmlElement* parentNode, ProjectBuildTarget* target)
 
707
{
 
708
    TiXmlElement* node = parentNode->FirstChildElement("Linker");
 
709
    if (!node)
 
710
        return; // no options
 
711
 
 
712
    TiXmlElement* child = node->FirstChildElement("Add");
 
713
    while (child)
 
714
    {
 
715
        wxString option = cbC2U(child->Attribute("option"));
 
716
        wxString dir = UnixFilename(cbC2U(child->Attribute("directory")));
 
717
        wxString lib = UnixFilename(cbC2U(child->Attribute("library")));
 
718
        if (!option.IsEmpty())
 
719
        {
 
720
            if (target)
 
721
                target->AddLinkerOption(option);
 
722
            else
 
723
                m_pProject->AddLinkerOption(option);
 
724
        }
 
725
        if (!lib.IsEmpty())
 
726
        {
 
727
            if (target)
 
728
                target->AddLinkLib(lib);
 
729
            else
 
730
                m_pProject->AddLinkLib(lib);
 
731
        }
 
732
        if (!dir.IsEmpty())
 
733
        {
 
734
            if (target)
 
735
                target->AddLibDir(dir);
 
736
            else
 
737
                m_pProject->AddLibDir(dir);
 
738
        }
 
739
 
 
740
        child = child->NextSiblingElement("Add");
 
741
    }
 
742
}
 
743
 
 
744
void ProjectLoader::DoIncludesOptions(TiXmlElement* parentNode, ProjectBuildTarget* target)
 
745
{
 
746
    TiXmlElement* node = parentNode->FirstChildElement("IncludeDirs");
 
747
    if (!node)
 
748
        return; // no options
 
749
 
 
750
    TiXmlElement* child = node->FirstChildElement("Add");
 
751
    while (child)
 
752
    {
 
753
        wxString option = UnixFilename(cbC2U(child->Attribute("option")));
 
754
        if (!option.IsEmpty())
 
755
        {
 
756
            if (target)
 
757
                target->AddIncludeDir(option);
 
758
            else
 
759
                m_pProject->AddIncludeDir(option);
 
760
        }
 
761
 
 
762
        child = child->NextSiblingElement("Add");
 
763
    }
 
764
}
 
765
 
 
766
void ProjectLoader::DoLibsOptions(TiXmlElement* parentNode, ProjectBuildTarget* target)
 
767
{
 
768
    TiXmlElement* node = parentNode->FirstChildElement("LibDirs");
 
769
    if (!node)
 
770
        return; // no options
 
771
 
 
772
    TiXmlElement* child = node->FirstChildElement("Add");
 
773
    while (child)
 
774
    {
 
775
        wxString option = cbC2U(child->Attribute("option"));
 
776
        if (!option.IsEmpty())
 
777
        {
 
778
            if (target)
 
779
                target->AddLibDir(option);
 
780
            else
 
781
                m_pProject->AddLibDir(option);
 
782
        }
 
783
 
 
784
        child = child->NextSiblingElement("Add");
 
785
    }
 
786
}
 
787
 
 
788
void ProjectLoader::DoExtraCommands(TiXmlElement* parentNode, ProjectBuildTarget* target)
 
789
{
 
790
    TiXmlElement* node = parentNode->FirstChildElement("ExtraCommands");
 
791
    while (node)
 
792
    {
 
793
        CompileOptionsBase* base = target ? target : (CompileOptionsBase*)m_pProject;
 
794
        TiXmlElement* child = node->FirstChildElement("Mode");
 
795
        while (child)
 
796
        {
 
797
            wxString mode = cbC2U(child->Attribute("after"));
 
798
            if (mode == _T("always"))
 
799
                base->SetAlwaysRunPostBuildSteps(true);
 
800
 
 
801
            child = child->NextSiblingElement("Mode");
 
802
        }
 
803
 
 
804
        child = node->FirstChildElement("Add");
 
805
        while (child)
 
806
        {
 
807
            wxString before;
 
808
            wxString after;
 
809
 
 
810
            if (child->Attribute("before"))
 
811
                before = cbC2U(child->Attribute("before"));
 
812
            if (child->Attribute("after"))
 
813
                after = cbC2U(child->Attribute("after"));
 
814
 
 
815
            if (!before.IsEmpty())
 
816
                base->AddCommandsBeforeBuild(before);
 
817
            if (!after.IsEmpty())
 
818
                base->AddCommandsAfterBuild(after);
 
819
 
 
820
            child = child->NextSiblingElement("Add");
 
821
        }
 
822
        node = node->NextSiblingElement("ExtraCommands");
 
823
    }
 
824
}
 
825
 
 
826
void ProjectLoader::DoEnvironment(TiXmlElement* parentNode, CompileOptionsBase* base)
 
827
{
 
828
    if (!base)
 
829
        return;
 
830
    TiXmlElement* node = parentNode->FirstChildElement("Environment");
 
831
    while (node)
 
832
    {
 
833
        TiXmlElement* child = node->FirstChildElement("Variable");
 
834
        while (child)
 
835
        {
 
836
            wxString name = cbC2U(child->Attribute("name"));
 
837
            wxString value = cbC2U(child->Attribute("value"));
 
838
            if (!name.IsEmpty())
 
839
                base->SetVar(name, UnixFilename(value));
 
840
 
 
841
            child = child->NextSiblingElement("Variable");
 
842
        }
 
843
        node = node->NextSiblingElement("Environment");
 
844
    }
 
845
}
 
846
 
 
847
void ProjectLoader::DoUnits(TiXmlElement* parentNode)
 
848
{
 
849
    Manager::Get()->GetLogManager()->DebugLog(_T("Loading project files..."));
 
850
    m_pProject->BeginAddFiles();
 
851
    int count = 0;
 
852
    TiXmlElement* unit = parentNode->FirstChildElement("Unit");
 
853
    while (unit)
 
854
    {
 
855
        wxString filename = cbC2U(unit->Attribute("filename"));
 
856
        if (!filename.IsEmpty())
 
857
        {
 
858
            ProjectFile* file = m_pProject->AddFile(-1, UnixFilename(filename));
 
859
            if (!file)
 
860
                Manager::Get()->GetLogManager()->DebugLog(_T("Can't load file ") + filename);
 
861
            else
 
862
            {
 
863
                ++count;
 
864
                DoUnitOptions(unit, file);
 
865
            }
 
866
        }
 
867
 
 
868
        unit = unit->NextSiblingElement("Unit");
 
869
    }
 
870
    m_pProject->EndAddFiles();
 
871
    Manager::Get()->GetLogManager()->DebugLog(F(_T("%d files loaded"), count));
 
872
}
 
873
 
 
874
void ProjectLoader::DoUnitOptions(TiXmlElement* parentNode, ProjectFile* file)
 
875
{
 
876
    int tempval = 0;
 
877
    bool foundCompile = false;
 
878
    bool foundLink = false;
 
879
    bool foundCompilerVar = false;
 
880
    bool foundTarget = false;
 
881
    bool noTarget = false;
 
882
 
 
883
//    Compiler* compiler = CompilerFactory::GetCompiler(m_pProject->GetCompilerID());
 
884
 
 
885
    TiXmlElement* node = parentNode->FirstChildElement("Option");
 
886
    while (node)
 
887
    {
 
888
        if (node->Attribute("compilerVar"))
 
889
        {
 
890
            file->compilerVar = cbC2U(node->Attribute("compilerVar"));
 
891
            foundCompilerVar = true;
 
892
        }
 
893
        //
 
894
        if (node->QueryIntAttribute("compile", &tempval) == TIXML_SUCCESS)
 
895
        {
 
896
            file->compile = tempval != 0;
 
897
            foundCompile = true;
 
898
        }
 
899
        //
 
900
        if (node->QueryIntAttribute("link", &tempval) == TIXML_SUCCESS)
 
901
        {
 
902
            file->link = tempval != 0;
 
903
            foundLink = true;
 
904
        }
 
905
        //
 
906
        if (node->QueryIntAttribute("weight", &tempval) == TIXML_SUCCESS)
 
907
            file->weight = tempval;
 
908
        //
 
909
        if (node->Attribute("virtualFolder"))
 
910
        {
 
911
            file->virtual_path = UnixFilename(cbC2U(node->Attribute("virtualFolder")));
 
912
        }
 
913
        //
 
914
        if (node->Attribute("buildCommand") && node->Attribute("compiler"))
 
915
        {
 
916
            wxString cmp = cbC2U(node->Attribute("compiler"));
 
917
            wxString tmp = cbC2U(node->Attribute("buildCommand"));
 
918
            if (!cmp.IsEmpty() && !tmp.IsEmpty())
 
919
            {
 
920
                tmp.Replace(_T("\\n"), _T("\n"));
 
921
                file->SetCustomBuildCommand(cmp, tmp);
 
922
                if (node->QueryIntAttribute("use", &tempval) == TIXML_SUCCESS)
 
923
                    file->SetUseCustomBuildCommand(cmp, tempval != 0);
 
924
            }
 
925
        }
 
926
        //
 
927
        if (node->Attribute("target"))
 
928
        {
 
929
            wxString targetName = cbC2U(node->Attribute("target"));
 
930
            if (!targetName.IsSameAs(_T("<{~None~}>")))
 
931
            {
 
932
                file->AddBuildTarget(targetName);
 
933
                foundTarget = true;
 
934
            }
 
935
            else
 
936
                noTarget = true;
 
937
        }
 
938
 
 
939
        node = node->NextSiblingElement("Option");
 
940
    }
 
941
 
 
942
    // pre 1.6 versions upgrade
 
943
    if (m_IsPre_1_6)
 
944
    {
 
945
        // make sure the "compile" and "link" flags are honored
 
946
        if (!foundCompile)
 
947
            file->compile = true;
 
948
        if (!foundLink)
 
949
            file->link = true;
 
950
        if (!foundCompilerVar)
 
951
            file->compilerVar = _T("CPP");
 
952
    }
 
953
 
 
954
    if (!foundTarget && !noTarget)
 
955
    {
 
956
        // add to all targets
 
957
        for (int i = 0; i < m_pProject->GetBuildTargetsCount(); ++i)
 
958
        {
 
959
            file->AddBuildTarget(m_pProject->GetBuildTarget(i)->GetTitle());
 
960
        }
 
961
 
 
962
        // use same targets for generated files
 
963
        for (size_t n = 0; n < file->generatedFiles.size(); ++n)
 
964
        {
 
965
            for (int i = 0; i < m_pProject->GetBuildTargetsCount(); ++i)
 
966
            {
 
967
                file->generatedFiles[n]->AddBuildTarget(m_pProject->GetBuildTarget(i)->GetTitle());
 
968
            }
 
969
        }
 
970
    }
 
971
}
 
972
 
 
973
// convenience function, used in Save()
 
974
TiXmlElement* ProjectLoader::AddElement(TiXmlElement* parent, const char* name, const char* attr, const wxString& attribute)
 
975
{
 
976
    TiXmlElement elem(name);
 
977
 
 
978
    if (attr)
 
979
    {
 
980
        elem.SetAttribute(attr, cbU2C(attribute));
 
981
    }
 
982
 
 
983
    return parent->InsertEndChild(elem)->ToElement();
 
984
}
 
985
 
 
986
// convenience function, used in Save()
 
987
TiXmlElement* ProjectLoader::AddElement(TiXmlElement* parent, const char* name, const char* attr, int attribute)
 
988
{
 
989
    TiXmlElement elem(name);
 
990
 
 
991
    if (attr)
 
992
    {
 
993
        elem.SetAttribute(attr, attribute);
 
994
    }
 
995
 
 
996
    return parent->InsertEndChild(elem)->ToElement();
 
997
}
 
998
 
 
999
// convenience function, used in Save()
 
1000
void ProjectLoader::AddArrayOfElements(TiXmlElement* parent, const char* name, const char* attr, const wxArrayString& array)
 
1001
{
 
1002
    if (!array.GetCount())
 
1003
        return;
 
1004
    for (unsigned int i = 0; i < array.GetCount(); ++i)
 
1005
    {
 
1006
        if (array[i].IsEmpty())
 
1007
            continue;
 
1008
        AddElement(parent, name, attr, array[i]);
 
1009
    }
 
1010
}
 
1011
 
 
1012
// convenience function, used in Save()
 
1013
void ProjectLoader::SaveEnvironment(TiXmlElement* parent, CompileOptionsBase* base)
 
1014
{
 
1015
    if (!base)
 
1016
        return;
 
1017
    const StringHash& v = base->GetAllVars();
 
1018
    if (v.empty())
 
1019
        return;
 
1020
    TiXmlElement* node = AddElement(parent, "Environment");
 
1021
    for (StringHash::const_iterator it = v.begin(); it != v.end(); ++it)
 
1022
    {
 
1023
        TiXmlElement* elem = AddElement(node, "Variable", "name", it->first);
 
1024
        elem->SetAttribute("value", cbU2C(it->second));
 
1025
    }
 
1026
}
 
1027
 
 
1028
bool ProjectLoader::Save(const wxString& filename)
 
1029
{
 
1030
    return Save(filename, 0);
 
1031
}
 
1032
 
 
1033
bool ProjectLoader::Save(const wxString& filename, TiXmlElement* pExtensions)
 
1034
{
 
1035
    if (ExportTargetAsProject(filename, wxEmptyString, pExtensions))
 
1036
    {
 
1037
        m_pProject->SetModified(false);
 
1038
        return true;
 
1039
    }
 
1040
    return false;
 
1041
}
 
1042
 
 
1043
bool ProjectLoader::ExportTargetAsProject(const wxString& filename, const wxString& onlyTarget, TiXmlElement* pExtensions)
 
1044
{
 
1045
    const char* ROOT_TAG = "CodeBlocks_project_file";
 
1046
 
 
1047
    TiXmlDocument doc;
 
1048
    doc.SetCondenseWhiteSpace(false);
 
1049
    doc.InsertEndChild(TiXmlDeclaration("1.0", "UTF-8", "yes"));
 
1050
    TiXmlElement* rootnode = static_cast<TiXmlElement*>(doc.InsertEndChild(TiXmlElement(ROOT_TAG)));
 
1051
    if (!rootnode)
 
1052
        return false;
 
1053
 
 
1054
//    Compiler* compiler = CompilerFactory::GetCompiler(m_pProject->GetCompilerID());
 
1055
 
 
1056
    rootnode->InsertEndChild(TiXmlElement("FileVersion"));
 
1057
    rootnode->FirstChildElement("FileVersion")->SetAttribute("major", PROJECT_FILE_VERSION_MAJOR);
 
1058
    rootnode->FirstChildElement("FileVersion")->SetAttribute("minor", PROJECT_FILE_VERSION_MINOR);
 
1059
 
 
1060
    rootnode->InsertEndChild(TiXmlElement("Project"));
 
1061
    TiXmlElement* prjnode = rootnode->FirstChildElement("Project");
 
1062
 
 
1063
    AddElement(prjnode, "Option", "title", m_pProject->GetTitle());
 
1064
    if (m_pProject->GetPlatforms() != spAll)
 
1065
    {
 
1066
        wxString platforms = GetStringFromPlatforms(m_pProject->GetPlatforms());
 
1067
        AddElement(prjnode, "Option", "platforms", platforms);
 
1068
    }
 
1069
    if (m_pProject->GetMakefile() != _T("Makefile"))
 
1070
        AddElement(prjnode, "Option", "makefile", m_pProject->GetMakefile());
 
1071
    if (m_pProject->IsMakefileCustom())
 
1072
        AddElement(prjnode, "Option", "makefile_is_custom", 1);
 
1073
    if (m_pProject->GetModeForPCH() != pchObjectDir)
 
1074
        AddElement(prjnode, "Option", "pch_mode", (int)m_pProject->GetModeForPCH());
 
1075
    if (!m_pProject->GetDefaultExecuteTarget().IsEmpty() && m_pProject->GetDefaultExecuteTarget() != m_pProject->GetFirstValidBuildTargetName())
 
1076
        AddElement(prjnode, "Option", "default_target", m_pProject->GetDefaultExecuteTarget());
 
1077
    AddElement(prjnode, "Option", "compiler", m_pProject->GetCompilerID());
 
1078
    if (m_pProject->GetVirtualFolders().GetCount() > 0)
 
1079
        AddElement(prjnode, "Option", "virtualFolders", GetStringFromArray(m_pProject->GetVirtualFolders(), _T(";")));
 
1080
    if (m_pProject->GetExtendedObjectNamesGeneration())
 
1081
        AddElement(prjnode, "Option", "extended_obj_names", 1);
 
1082
    if (m_pProject->GetShowNotesOnLoad() || !m_pProject->GetNotes().IsEmpty())
 
1083
    {
 
1084
        TiXmlElement* notesBase = AddElement(prjnode, "Option", "show_notes", m_pProject->GetShowNotesOnLoad() ? 1 : 0);
 
1085
        if (!m_pProject->GetNotes().IsEmpty())
 
1086
        {
 
1087
            TiXmlElement* notes = AddElement(notesBase, "notes");
 
1088
            TiXmlText t(m_pProject->GetNotes().mb_str(wxConvUTF8));
 
1089
            t.SetCDATA(true);
 
1090
            notes->InsertEndChild(t);
 
1091
        }
 
1092
    }
 
1093
 
 
1094
    if (m_pProject->MakeCommandsModified())
 
1095
    {
 
1096
        TiXmlElement* makenode = AddElement(prjnode, "MakeCommands");
 
1097
        AddElement(makenode, "Build", "command", m_pProject->GetMakeCommandFor(mcBuild));
 
1098
        AddElement(makenode, "CompileFile", "command", m_pProject->GetMakeCommandFor(mcCompileFile));
 
1099
        AddElement(makenode, "Clean", "command", m_pProject->GetMakeCommandFor(mcClean));
 
1100
        AddElement(makenode, "DistClean", "command", m_pProject->GetMakeCommandFor(mcDistClean));
 
1101
    }
 
1102
 
 
1103
    prjnode->InsertEndChild(TiXmlElement("Build"));
 
1104
    TiXmlElement* buildnode = prjnode->FirstChildElement("Build");
 
1105
 
 
1106
    for (size_t x = 0; x < m_pProject->GetBuildScripts().GetCount(); ++x)
 
1107
    {
 
1108
        AddElement(buildnode, "Script", "file", m_pProject->GetBuildScripts().Item(x));
 
1109
    }
 
1110
 
 
1111
    // now decide which target we 're exporting.
 
1112
    // remember that if onlyTarget is empty, we export all targets (i.e. normal save).
 
1113
    ProjectBuildTarget* onlytgt = m_pProject->GetBuildTarget(onlyTarget);
 
1114
 
 
1115
    for (int i = 0; i < m_pProject->GetBuildTargetsCount(); ++i)
 
1116
    {
 
1117
        ProjectBuildTarget* target = m_pProject->GetBuildTarget(i);
 
1118
        if (!target)
 
1119
            break;
 
1120
 
 
1121
        // skip every target except the desired one
 
1122
        if (onlytgt && onlytgt != target)
 
1123
            continue;
 
1124
 
 
1125
        TiXmlElement* tgtnode = AddElement(buildnode, "Target", "title", target->GetTitle());
 
1126
        if (target->GetPlatforms() != spAll)
 
1127
        {
 
1128
            wxString platforms = GetStringFromPlatforms(target->GetPlatforms());
 
1129
            AddElement(tgtnode, "Option", "platforms", platforms);
 
1130
        }
 
1131
        if (target->GetTargetType() != ttCommandsOnly)
 
1132
        {
 
1133
            TargetFilenameGenerationPolicy prefixPolicy;
 
1134
            TargetFilenameGenerationPolicy extensionPolicy;
 
1135
            target->GetTargetFilenameGenerationPolicy(prefixPolicy, extensionPolicy);
 
1136
 
 
1137
            wxString outputFileName = target->GetOutputFilename();
 
1138
            if (extensionPolicy == tgfpPlatformDefault)
 
1139
            {
 
1140
                wxFileName fname(outputFileName);
 
1141
                fname.ClearExt();
 
1142
                outputFileName = fname.GetFullPath();
 
1143
            }
 
1144
            TiXmlElement* outnode = AddElement(tgtnode, "Option", "output", outputFileName);
 
1145
            outnode->SetAttribute("prefix_auto", prefixPolicy == tgfpPlatformDefault ? "1" : "0");
 
1146
            outnode->SetAttribute("extension_auto", extensionPolicy == tgfpPlatformDefault ? "1" : "0");
 
1147
 
 
1148
            if (target->GetWorkingDir() != _T("."))
 
1149
                AddElement(tgtnode, "Option", "working_dir", target->GetWorkingDir());
 
1150
            if (target->GetObjectOutput() != _T(".objs"))
 
1151
                AddElement(tgtnode, "Option", "object_output", target->GetObjectOutput());
 
1152
            if (target->GetDepsOutput() != _T(".deps"))
 
1153
                AddElement(tgtnode, "Option", "deps_output", target->GetDepsOutput());
 
1154
        }
 
1155
        if (!target->GetExternalDeps().IsEmpty())
 
1156
            AddElement(tgtnode, "Option", "external_deps", target->GetExternalDeps());
 
1157
        if (!target->GetAdditionalOutputFiles().IsEmpty())
 
1158
            AddElement(tgtnode, "Option", "additional_output", target->GetAdditionalOutputFiles());
 
1159
        AddElement(tgtnode, "Option", "type", target->GetTargetType());
 
1160
        AddElement(tgtnode, "Option", "compiler", target->GetCompilerID());
 
1161
        if (target->GetTargetType() == ttConsoleOnly && !target->GetUseConsoleRunner())
 
1162
            AddElement(tgtnode, "Option", "use_console_runner", 0);
 
1163
        if (!target->GetExecutionParameters().IsEmpty())
 
1164
            AddElement(tgtnode, "Option", "parameters", target->GetExecutionParameters());
 
1165
        if (!target->GetHostApplication().IsEmpty())
 
1166
            AddElement(tgtnode, "Option", "host_application", target->GetHostApplication());
 
1167
        // used in versions prior to 1.5
 
1168
//        if (target->GetIncludeInTargetAll())
 
1169
//            AddElement(tgtnode, "Option", "includeInTargetAll", 1);
 
1170
        if ((target->GetTargetType() == ttStaticLib || target->GetTargetType() == ttDynamicLib) && target->GetCreateDefFile())
 
1171
            AddElement(tgtnode, "Option", "createDefFile", 1);
 
1172
        if (target->GetTargetType() == ttDynamicLib && target->GetCreateStaticLib())
 
1173
            AddElement(tgtnode, "Option", "createStaticLib", 1);
 
1174
        if (target->GetOptionRelation(ortCompilerOptions) != 3) // 3 is the default
 
1175
            AddElement(tgtnode, "Option", "projectCompilerOptionsRelation", target->GetOptionRelation(ortCompilerOptions));
 
1176
        if (target->GetOptionRelation(ortLinkerOptions) != 3) // 3 is the default
 
1177
            AddElement(tgtnode, "Option", "projectLinkerOptionsRelation", target->GetOptionRelation(ortLinkerOptions));
 
1178
        if (target->GetOptionRelation(ortIncludeDirs) != 3) // 3 is the default
 
1179
            AddElement(tgtnode, "Option", "projectIncludeDirsRelation", target->GetOptionRelation(ortIncludeDirs));
 
1180
        if (target->GetOptionRelation(ortResDirs) != 3) // 3 is the default
 
1181
            AddElement(tgtnode, "Option", "projectResourceIncludeDirsRelation", target->GetOptionRelation(ortResDirs));
 
1182
        if (target->GetOptionRelation(ortLibDirs) != 3) // 3 is the default
 
1183
            AddElement(tgtnode, "Option", "projectLibDirsRelation", target->GetOptionRelation(ortLibDirs));
 
1184
 
 
1185
        for (size_t x = 0; x < target->GetBuildScripts().GetCount(); ++x)
 
1186
        {
 
1187
            AddElement(tgtnode, "Script", "file", target->GetBuildScripts().Item(x));
 
1188
        }
 
1189
 
 
1190
        TiXmlElement* node = AddElement(tgtnode, "Compiler");
 
1191
        AddArrayOfElements(node, "Add", "option", target->GetCompilerOptions());
 
1192
        AddArrayOfElements(node, "Add", "directory", target->GetIncludeDirs());
 
1193
        if (node->NoChildren())
 
1194
            tgtnode->RemoveChild(node);
 
1195
 
 
1196
        node = AddElement(tgtnode, "ResourceCompiler");
 
1197
        AddArrayOfElements(node, "Add", "directory", target->GetResourceIncludeDirs());
 
1198
        if (node->NoChildren())
 
1199
            tgtnode->RemoveChild(node);
 
1200
 
 
1201
        node = AddElement(tgtnode, "Linker");
 
1202
        AddArrayOfElements(node, "Add", "option", target->GetLinkerOptions());
 
1203
        AddArrayOfElements(node, "Add", "library", target->GetLinkLibs());
 
1204
        AddArrayOfElements(node, "Add", "directory", target->GetLibDirs());
 
1205
        if (node->NoChildren())
 
1206
            tgtnode->RemoveChild(node);
 
1207
 
 
1208
        node = AddElement(tgtnode, "ExtraCommands");
 
1209
        AddArrayOfElements(node, "Add", "before", target->GetCommandsBeforeBuild());
 
1210
        AddArrayOfElements(node, "Add", "after", target->GetCommandsAfterBuild());
 
1211
        if (node->NoChildren())
 
1212
            tgtnode->RemoveChild(node);
 
1213
        else
 
1214
        {
 
1215
            if (target->GetAlwaysRunPostBuildSteps())
 
1216
                AddElement(node, "Mode", "after", wxString(_T("always")));
 
1217
        }
 
1218
 
 
1219
        SaveEnvironment(tgtnode, target);
 
1220
 
 
1221
        if (target->MakeCommandsModified())
 
1222
        {
 
1223
            TiXmlElement* makenode = AddElement(tgtnode, "MakeCommands");
 
1224
            AddElement(makenode, "Build", "command", target->GetMakeCommandFor(mcBuild));
 
1225
            AddElement(makenode, "CompileFile", "command", target->GetMakeCommandFor(mcCompileFile));
 
1226
            AddElement(makenode, "Clean", "command", target->GetMakeCommandFor(mcClean));
 
1227
            AddElement(makenode, "DistClean", "command", target->GetMakeCommandFor(mcDistClean));
 
1228
        }
 
1229
    }
 
1230
 
 
1231
    // virtuals only for whole project
 
1232
    if (onlyTarget.IsEmpty())
 
1233
    {
 
1234
        TiXmlElement* virtnode = AddElement(prjnode, "VirtualTargets");
 
1235
        wxArrayString virtuals = m_pProject->GetVirtualBuildTargets();
 
1236
        for (size_t i = 0; i < virtuals.GetCount(); ++i)
 
1237
        {
 
1238
            const wxArrayString& group = m_pProject->GetVirtualBuildTargetGroup(virtuals[i]);
 
1239
            wxString groupStr = GetStringFromArray(group, _T(";"));
 
1240
            if (!groupStr.IsEmpty())
 
1241
            {
 
1242
                TiXmlElement* elem = AddElement(virtnode, "Add", "alias", virtuals[i]);
 
1243
                elem->SetAttribute("targets", cbU2C(groupStr));
 
1244
            }
 
1245
        }
 
1246
        if (virtnode->NoChildren())
 
1247
            prjnode->RemoveChild(virtnode);
 
1248
    }
 
1249
 
 
1250
    SaveEnvironment(buildnode, m_pProject);
 
1251
 
 
1252
    TiXmlElement* node = AddElement(prjnode, "Compiler");
 
1253
    AddArrayOfElements(node, "Add", "option", m_pProject->GetCompilerOptions());
 
1254
    AddArrayOfElements(node, "Add", "directory", m_pProject->GetIncludeDirs());
 
1255
    if (node->NoChildren())
 
1256
        prjnode->RemoveChild(node);
 
1257
 
 
1258
    node = AddElement(prjnode, "ResourceCompiler");
 
1259
    AddArrayOfElements(node, "Add", "directory", m_pProject->GetResourceIncludeDirs());
 
1260
    if (node->NoChildren())
 
1261
        prjnode->RemoveChild(node);
 
1262
 
 
1263
    node = AddElement(prjnode, "Linker");
 
1264
    AddArrayOfElements(node, "Add", "option", m_pProject->GetLinkerOptions());
 
1265
    AddArrayOfElements(node, "Add", "library", m_pProject->GetLinkLibs());
 
1266
    AddArrayOfElements(node, "Add", "directory", m_pProject->GetLibDirs());
 
1267
    if (node->NoChildren())
 
1268
        prjnode->RemoveChild(node);
 
1269
 
 
1270
    node = AddElement(prjnode, "ExtraCommands");
 
1271
    AddArrayOfElements(node, "Add", "before", m_pProject->GetCommandsBeforeBuild());
 
1272
    AddArrayOfElements(node, "Add", "after", m_pProject->GetCommandsAfterBuild());
 
1273
    if (node->NoChildren())
 
1274
        prjnode->RemoveChild(node);
 
1275
    else
 
1276
    {
 
1277
        if (m_pProject->GetAlwaysRunPostBuildSteps())
 
1278
            AddElement(node, "Mode", "after", wxString(_T("always")));
 
1279
    }
 
1280
 
 
1281
    int count = m_pProject->GetFilesCount();
 
1282
    for (int i = 0; i < count; ++i)
 
1283
    {
 
1284
        ProjectFile* f = m_pProject->GetFile(i);
 
1285
 
 
1286
        // do not save auto-generated files
 
1287
        if (f->autoGeneratedBy)
 
1288
            continue;
 
1289
 
 
1290
        // do not save project files that do not belong in the target we 're exporting
 
1291
        if (onlytgt && !onlytgt->GetFilesList().Find(f))
 
1292
            continue;
 
1293
 
 
1294
        FileType ft = FileTypeOf(f->relativeFilename);
 
1295
 
 
1296
        TiXmlElement* unitnode = AddElement(prjnode, "Unit", "filename", f->relativeFilename);
 
1297
        if (!f->compilerVar.IsEmpty())
 
1298
        {
 
1299
            wxString ext = f->relativeFilename.AfterLast(_T('.')).Lower();
 
1300
            if (f->compilerVar != _T("CC") && (ext.IsSameAs(FileFilters::C_EXT)))
 
1301
                AddElement(unitnode, "Option", "compilerVar", f->compilerVar);
 
1302
#ifdef __WXMSW__
 
1303
            else if (f->compilerVar != _T("WINDRES") && ext.IsSameAs(FileFilters::RESOURCE_EXT))
 
1304
                AddElement(unitnode, "Option", "compilerVar", f->compilerVar);
 
1305
#endif
 
1306
            else if (f->compilerVar != _T("CPP")) // default
 
1307
                AddElement(unitnode, "Option", "compilerVar", f->compilerVar);
 
1308
        }
 
1309
 
 
1310
        if (f->compile != (ft == ftSource || ft == ftResource))
 
1311
        {
 
1312
            AddElement(unitnode, "Option", "compile", f->compile ? 1 : 0);
 
1313
        }
 
1314
        if (f->link !=
 
1315
                (ft == ftSource ||
 
1316
                ft == ftResource ||
 
1317
                ft == ftObject ||
 
1318
                ft == ftResourceBin ||
 
1319
                ft == ftStaticLib))
 
1320
        {
 
1321
            AddElement(unitnode, "Option", "link", f->link ? 1 : 0);
 
1322
        }
 
1323
        if (f->weight != 50)
 
1324
            AddElement(unitnode, "Option", "weight", f->weight);
 
1325
        if (!f->virtual_path.IsEmpty())
 
1326
            AddElement(unitnode, "Option", "virtualFolder", f->virtual_path);
 
1327
 
 
1328
        // loop and save custom build commands
 
1329
        for (pfCustomBuildMap::iterator it = f->customBuild.begin(); it != f->customBuild.end(); ++it)
 
1330
        {
 
1331
            pfCustomBuild& pfcb = it->second;
 
1332
            if (!pfcb.buildCommand.IsEmpty())
 
1333
            {
 
1334
                wxString tmp = pfcb.buildCommand;
 
1335
                tmp.Replace(_T("\n"), _T("\\n"));
 
1336
                TiXmlElement* elem = AddElement(unitnode, "Option", "compiler", it->first);
 
1337
                elem->SetAttribute("use", pfcb.useCustomBuildCommand ? "1" : "0");
 
1338
                elem->SetAttribute("buildCommand", cbU2C(tmp));
 
1339
            }
 
1340
        }
 
1341
 
 
1342
        if ((int)f->buildTargets.GetCount() != m_pProject->GetBuildTargetsCount())
 
1343
        {
 
1344
            for (unsigned int x = 0; x < f->buildTargets.GetCount(); ++x)
 
1345
                AddElement(unitnode, "Option", "target", f->buildTargets[x]);
 
1346
        }
 
1347
 
 
1348
        /* Add a target with a weird name if no targets are present. *
 
1349
         * This will help us detecting a file with no targets.       */
 
1350
        if ((int)f->buildTargets.GetCount() == 0)
 
1351
        {
 
1352
            AddElement(unitnode, "Option", "target", _T("<{~None~}>"));
 
1353
        }
 
1354
    }
 
1355
 
 
1356
    // as a last step, run all hooked callbacks
 
1357
    TiXmlElement* extnode = pExtensions
 
1358
                            ? prjnode->InsertEndChild(*pExtensions)->ToElement()
 
1359
                            : AddElement(prjnode, "Extensions");
 
1360
    if (ProjectLoaderHooks::HasRegisteredHooks() && extnode)
 
1361
    {
 
1362
        ProjectLoaderHooks::CallHooks(m_pProject, extnode, false);
 
1363
    }
 
1364
 
 
1365
    return cbSaveTinyXMLDocument(&doc, filename);
 
1366
}
 
1367
 
 
1368
wxString ProjectLoader::GetValidCompilerID(const wxString& proposal, const wxString& scope)
 
1369
{
 
1370
    if (CompilerFactory::GetCompiler(proposal))
 
1371
        return proposal;
 
1372
 
 
1373
    // check the map; maybe we asked the user before
 
1374
    CompilerSubstitutes::iterator it = m_CompilerSubstitutes.find(proposal);
 
1375
    if (it != m_CompilerSubstitutes.end())
 
1376
        return it->second;
 
1377
 
 
1378
    Compiler* compiler = 0;
 
1379
 
 
1380
    // if compiler is a number, then this is an older version of the project file
 
1381
    // propose the same compiler by index
 
1382
    if (!proposal.IsEmpty())
 
1383
    {
 
1384
        long int idx = -1;
 
1385
        if (proposal.ToLong(&idx))
 
1386
            compiler = CompilerFactory::GetCompiler(idx);
 
1387
    }
 
1388
 
 
1389
    if (!compiler)
 
1390
    {
 
1391
        if(!(Manager::Get()->GetConfigManager(_T("app"))->ReadBool(_T("/environment/ignore_invalid_targets"), false)))
 
1392
        {
 
1393
            wxString msg;
 
1394
            msg.Printf(_("The defined compiler for %s cannot be located (ID: %s).\n"
 
1395
                        "Please choose the compiler you want to use instead and click \"OK\".\n"
 
1396
                        "If you click \"Cancel\", the project/target will be excluded from the build."), scope.c_str(),
 
1397
                        proposal.c_str());
 
1398
            compiler = CompilerFactory::SelectCompilerUI(msg);
 
1399
        }
 
1400
    }
 
1401
 
 
1402
    if (!compiler)
 
1403
    {
 
1404
        // allow for invalid compiler IDs to be preserved...
 
1405
        m_CompilerSubstitutes[proposal] = proposal;
 
1406
        return proposal;
 
1407
    }
 
1408
 
 
1409
    m_OpenDirty = true;
 
1410
 
 
1411
    // finally, keep the user selection in the map so we don't ask him again
 
1412
    m_CompilerSubstitutes[proposal] = compiler->GetID();
 
1413
    return compiler->GetID();
 
1414
}