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
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 $
10
#include "sdk_precomp.h"
13
#include <wx/confbase.h>
14
#include <wx/fileconf.h>
16
#include <wx/filename.h>
17
#include <wx/msgdlg.h>
18
#include <wx/stopwatch.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"
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"
36
ProjectLoader::ProjectLoader(cbProject* project)
37
: m_pProject(project),
40
m_1_4_to_1_5_deftarget(-1),
46
ProjectLoader::~ProjectLoader()
51
bool ProjectLoader::Open(const wxString& filename)
53
return Open(filename, 0);
56
bool ProjectLoader::Open(const wxString& filename, TiXmlElement** ppExtensions)
58
LogManager* pMsg = Manager::Get()->GetLogManager();
63
pMsg->DebugLog(_T("Loading project file..."));
65
if (!TinyXML::LoadDocument(filename, &doc))
68
pMsg->DebugLog(_T("Parsing project file..."));
72
root = doc.FirstChildElement("CodeBlocks_project_file");
76
root = doc.FirstChildElement("Code::Blocks_project_file");
79
pMsg->DebugLog(_T("Not a valid Code::Blocks project file..."));
83
proj = root->FirstChildElement("Project");
86
pMsg->DebugLog(_T("No 'Project' element in file..."));
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)
95
int major = PROJECT_FILE_VERSION_MAJOR;
96
int minor = PROJECT_FILE_VERSION_MINOR;
97
version->QueryIntAttribute("major", &major);
98
version->QueryIntAttribute("minor", &minor);
100
m_IsPre_1_6 = major < 1 || (major == 1 && minor < 6);
103
(major == 1 && minor < 2))
106
pMsg->DebugLog(F(_T("Project version is %d.%d. Defaults have changed since then..."), major, minor));
109
else if (major >= PROJECT_FILE_VERSION_MAJOR && minor > PROJECT_FILE_VERSION_MINOR)
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..."),
122
// use one message for all changes
126
// 1.5 -> 1.6: values matching defaults are not written to <Unit> sections
127
if (major == 1 && minor == 5)
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");
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");
143
// 1.4 -> 1.5: updated custom build command per-project file
144
if (major == 1 && minor == 4)
146
msg << _("1.4 to 1.5:\n");
147
msg << _(" * added virtual build targets.\n");
151
// 1.3 -> 1.4: updated custom build command per-project file
152
if (major == 1 && minor == 3)
154
msg << _("1.3 to 1.4:\n");
155
msg << _(" * changed the way custom file build commands are stored (no auto-conversion).\n");
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"),
171
PROJECT_FILE_VERSION_MAJOR,
172
PROJECT_FILE_VERSION_MINOR));
173
AnnoyingDialog dlg(_("Project file format changed"),
181
if (!warn_msg.IsEmpty())
183
warn_msg.Prepend(_("!!! WARNING !!!\n\n"));
184
AnnoyingDialog dlg(_("Project file upgrade warning"),
194
DoProjectOptions(proj);
196
DoCompilerOptions(proj);
197
DoResourceCompilerOptions(proj);
198
DoLinkerOptions(proj);
199
DoIncludesOptions(proj);
201
DoExtraCommands(proj);
204
// if targets still use the "build with all" flag,
205
// it's time for conversion
206
if (!m_pProject->HasVirtualBuildTarget(_T("All")))
209
for (int i = 0; i < m_pProject->GetBuildTargetsCount(); ++i)
211
ProjectBuildTarget* bt = m_pProject->GetBuildTarget(i);
212
if (bt && bt->GetIncludeInTargetAll())
213
all.Add(bt->GetTitle());
217
m_pProject->DefineVirtualBuildTarget(_T("All"), all);
222
// convert old deftarget int to string
223
if (m_1_4_to_1_5_deftarget != -1)
225
ProjectBuildTarget* bt = m_pProject->GetBuildTarget(m_1_4_to_1_5_deftarget);
227
m_pProject->SetDefaultExecuteTarget(bt->GetTitle());
233
// as a last step, run all hooked callbacks
234
TiXmlElement* node = proj->FirstChildElement("Extensions");
238
*ppExtensions = new TiXmlElement(*node);
239
ProjectLoaderHooks::CallHooks(m_pProject, node, true);
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...
254
// do something important based on version
255
// wxString major = version->Attribute("major");
256
// wxString minor = version->Attribute("minor");
259
pMsg->DebugLog(wxString(_T("Done loading project in ")) << wxString::Format(_T("%d"), (int) sw.Time()) << _T("ms"));
263
void ProjectLoader::ConvertVersion_Pre_1_1()
265
// ask to detect linker libraries and move them to the new
266
// CompileOptionsBase linker libs container
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)
276
ConvertLibraries(m_pProject);
278
for (int i = 0; i < m_pProject->GetBuildTargetsCount(); ++i)
280
ConvertLibraries(m_pProject->GetBuildTarget(i));
286
void ProjectLoader::ConvertLibraries(CompileTargetBase* object)
288
wxArrayString linkerOpts = object->GetLinkerOptions();
289
wxArrayString linkLibs = object->GetLinkLibs();
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();
298
while (i < linkerOpts.GetCount())
300
wxString opt = linkerOpts[i];
301
if (!linkLib.IsEmpty() && opt.StartsWith(linkLib))
304
wxString ext = compiler->GetSwitches().libExtension;
307
linkLibs.Add(compiler->GetSwitches().libPrefix + opt + ext);
308
linkerOpts.RemoveAt(i, 1);
310
else if (opt.Length() > libExtLen && opt.Right(libExtLen) == libExt)
313
linkerOpts.RemoveAt(i, 1);
319
object->SetLinkerOptions(linkerOpts);
320
object->SetLinkLibs(linkLibs);
323
void ProjectLoader::DoMakeCommands(TiXmlElement* parentNode, CompileTargetBase* target)
326
return; // no options
330
node = parentNode->FirstChildElement("Build");
331
if (node && node->Attribute("command"))
332
target->SetMakeCommandFor(mcBuild, cbC2U(node->Attribute("command")));
334
node = parentNode->FirstChildElement("CompileFile");
335
if (node && node->Attribute("command"))
336
target->SetMakeCommandFor(mcCompileFile, cbC2U(node->Attribute("command")));
338
node = parentNode->FirstChildElement("Clean");
339
if (node && node->Attribute("command"))
340
target->SetMakeCommandFor(mcClean, cbC2U(node->Attribute("command")));
342
node = parentNode->FirstChildElement("DistClean");
343
if (node && node->Attribute("command"))
344
target->SetMakeCommandFor(mcDistClean, cbC2U(node->Attribute("command")));
347
void ProjectLoader::DoVirtualTargets(TiXmlElement* parentNode)
352
TiXmlElement* node = parentNode->FirstChildElement("Add");
354
return; // no virtual targets
358
if (node->Attribute("alias") && node->Attribute("targets"))
360
wxString alias = cbC2U(node->Attribute("alias"));
361
wxString targets = cbC2U(node->Attribute("targets"));
362
wxArrayString arr = GetArrayFromString(targets, _T(";"), true);
364
m_pProject->DefineVirtualBuildTarget(alias, arr);
367
node = node->NextSiblingElement("Add");
371
void ProjectLoader::DoProjectOptions(TiXmlElement* parentNode)
373
TiXmlElement* node = parentNode->FirstChildElement("Option");
375
return; // no options
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;
389
// loop through all options
392
if (node->Attribute("title"))
394
title = cbC2U(node->Attribute("title"));
395
if (title.Trim().IsEmpty())
396
title = _T("untitled");
399
else if (node->Attribute("platforms"))
400
platformsFinal = GetPlatformsFromString(cbC2U(node->Attribute("platforms")));
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"));
405
else if (node->Attribute("makefile_is_custom"))
406
makefile_custom = strncmp(node->Attribute("makefile_is_custom"), "1", 1) == 0;
408
// old default_target (int) node
409
else if (node->QueryIntAttribute("default_target", &m_1_4_to_1_5_deftarget) == TIXML_SUCCESS)
414
else if (node->Attribute("default_target"))
415
defaultTarget = cbC2U(node->Attribute("default_target"));
417
else if (node->Attribute("compiler"))
418
compilerId = GetValidCompilerID(cbC2U(node->Attribute("compiler")), _T("the project"));
420
else if (node->Attribute("extended_obj_names"))
421
extendedObjectNames = strncmp(node->Attribute("extended_obj_names"), "1", 1) == 0;
423
else if (node->Attribute("pch_mode"))
424
pch_mode = (PCHMode)atoi(node->Attribute("pch_mode"));
426
else if (node->Attribute("virtualFolders"))
427
vfolders = GetArrayFromString(cbC2U(node->Attribute("virtualFolders")), _T(";"));
429
else if (node->Attribute("show_notes"))
431
TiXmlHandle parentHandle(node);
432
TiXmlText* t = (TiXmlText *) parentHandle.FirstChild("notes").FirstChild().Node();
434
notes = cbC2U(t->Value());
435
showNotes = !notes.IsEmpty() && strncmp(node->Attribute("show_notes"), "1", 1) == 0;
438
node = node->NextSiblingElement("Option");
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);
453
DoMakeCommands(parentNode->FirstChildElement("MakeCommands"), m_pProject);
454
DoVirtualTargets(parentNode->FirstChildElement("VirtualTargets"));
457
void ProjectLoader::DoBuild(TiXmlElement* parentNode)
459
TiXmlElement* node = parentNode->FirstChildElement("Build");
462
TiXmlElement* opt = node->FirstChildElement("Script");
465
if (opt->Attribute("file"))
466
m_pProject->AddBuildScript(cbC2U(opt->Attribute("file")));
468
opt = opt->NextSiblingElement("Script");
472
DoEnvironment(node, m_pProject);
473
node = node->NextSiblingElement("Build");
477
void ProjectLoader::DoBuildTarget(TiXmlElement* parentNode)
479
TiXmlElement* node = parentNode->FirstChildElement("Target");
481
return; // no options
485
ProjectBuildTarget* target = 0L;
486
wxString title = cbC2U(node->Attribute("title"));
487
if (!title.IsEmpty())
488
target = m_pProject->AddBuildTarget(title);
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);
503
node = node->NextSiblingElement("Target");
507
void ProjectLoader::DoBuildTargetOptions(TiXmlElement* parentNode, ProjectBuildTarget* target)
509
TiXmlElement* node = parentNode->FirstChildElement("Option");
511
return; // no options
513
bool use_console_runner = true;
515
wxString working_dir;
517
wxString deps_output;
521
int platformsFinal = spAll;
522
wxString compilerId = m_pProject->GetCompilerID();
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;
538
if (node->Attribute("platforms"))
539
platformsFinal = GetPlatformsFromString(cbC2U(node->Attribute("platforms")));
541
if (node->Attribute("use_console_runner"))
542
use_console_runner = strncmp(node->Attribute("use_console_runner"), "0", 1) != 0;
544
if (node->Attribute("output"))
545
output = UnixFilename(cbC2U(node->Attribute("output")));
547
if (node->Attribute("prefix_auto"))
548
prefixPolicy = atoi(node->Attribute("prefix_auto")) == 1 ? tgfpPlatformDefault : tgfpNone;
550
if (node->Attribute("extension_auto"))
551
extensionPolicy = atoi(node->Attribute("extension_auto")) == 1 ? tgfpPlatformDefault : tgfpNone;
553
if (node->Attribute("working_dir"))
554
working_dir = UnixFilename(cbC2U(node->Attribute("working_dir")));
556
if (node->Attribute("object_output"))
557
obj_output = UnixFilename(cbC2U(node->Attribute("object_output")));
559
if (node->Attribute("deps_output"))
560
deps_output = UnixFilename(cbC2U(node->Attribute("deps_output")));
562
if (node->Attribute("external_deps"))
563
deps = UnixFilename(cbC2U(node->Attribute("external_deps")));
565
if (node->Attribute("additional_output"))
566
added = UnixFilename(cbC2U(node->Attribute("additional_output")));
568
if (node->Attribute("type"))
569
type = atoi(node->Attribute("type"));
571
if (node->Attribute("compiler"))
572
compilerId = GetValidCompilerID(cbC2U(node->Attribute("compiler")), target->GetTitle());
574
if (node->Attribute("parameters"))
575
parameters = cbC2U(node->Attribute("parameters"));
577
if (node->Attribute("host_application"))
578
hostApplication = UnixFilename(cbC2U(node->Attribute("host_application")));
580
// used in versions prior to 1.5
581
if (node->Attribute("includeInTargetAll"))
582
includeInTargetAll = atoi(node->Attribute("includeInTargetAll")) != 0;
584
if (node->Attribute("createDefFile"))
585
createDefFile = atoi(node->Attribute("createDefFile")) != 0;
587
if (node->Attribute("createStaticLib"))
588
createStaticLib = atoi(node->Attribute("createStaticLib")) != 0;
590
if (node->Attribute("projectCompilerOptionsRelation"))
591
projectCompilerOptionsRelation = atoi(node->Attribute("projectCompilerOptionsRelation"));
593
if (node->Attribute("projectLinkerOptionsRelation"))
594
projectLinkerOptionsRelation = atoi(node->Attribute("projectLinkerOptionsRelation"));
596
if (node->Attribute("projectIncludeDirsRelation"))
597
projectIncludeDirsRelation = atoi(node->Attribute("projectIncludeDirsRelation"));
599
if (node->Attribute("projectLibDirsRelation"))
600
projectLibDirsRelation = atoi(node->Attribute("projectLibDirsRelation"));
602
if (node->Attribute("projectResourceIncludeDirsRelation"))
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;
611
node = node->NextSiblingElement("Option");
614
node = parentNode->FirstChildElement("Script");
617
if (node->Attribute("file"))
618
target->AddBuildScript(cbC2U(node->Attribute("file")));
620
node = node->NextSiblingElement("Script");
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);
650
DoMakeCommands(parentNode->FirstChildElement("MakeCommands"), target);
654
void ProjectLoader::DoCompilerOptions(TiXmlElement* parentNode, ProjectBuildTarget* target)
656
TiXmlElement* node = parentNode->FirstChildElement("Compiler");
658
return; // no options
660
TiXmlElement* child = node->FirstChildElement("Add");
663
wxString option = cbC2U(child->Attribute("option"));
664
wxString dir = cbC2U(child->Attribute("directory"));
665
if (!option.IsEmpty())
668
target->AddCompilerOption(option);
670
m_pProject->AddCompilerOption(option);
675
target->AddIncludeDir(dir);
677
m_pProject->AddIncludeDir(dir);
680
child = child->NextSiblingElement("Add");
684
void ProjectLoader::DoResourceCompilerOptions(TiXmlElement* parentNode, ProjectBuildTarget* target)
686
TiXmlElement* node = parentNode->FirstChildElement("ResourceCompiler");
688
return; // no options
690
TiXmlElement* child = node->FirstChildElement("Add");
693
wxString dir = cbC2U(child->Attribute("directory"));
697
target->AddResourceIncludeDir(dir);
699
m_pProject->AddResourceIncludeDir(dir);
702
child = child->NextSiblingElement("Add");
706
void ProjectLoader::DoLinkerOptions(TiXmlElement* parentNode, ProjectBuildTarget* target)
708
TiXmlElement* node = parentNode->FirstChildElement("Linker");
710
return; // no options
712
TiXmlElement* child = node->FirstChildElement("Add");
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())
721
target->AddLinkerOption(option);
723
m_pProject->AddLinkerOption(option);
728
target->AddLinkLib(lib);
730
m_pProject->AddLinkLib(lib);
735
target->AddLibDir(dir);
737
m_pProject->AddLibDir(dir);
740
child = child->NextSiblingElement("Add");
744
void ProjectLoader::DoIncludesOptions(TiXmlElement* parentNode, ProjectBuildTarget* target)
746
TiXmlElement* node = parentNode->FirstChildElement("IncludeDirs");
748
return; // no options
750
TiXmlElement* child = node->FirstChildElement("Add");
753
wxString option = UnixFilename(cbC2U(child->Attribute("option")));
754
if (!option.IsEmpty())
757
target->AddIncludeDir(option);
759
m_pProject->AddIncludeDir(option);
762
child = child->NextSiblingElement("Add");
766
void ProjectLoader::DoLibsOptions(TiXmlElement* parentNode, ProjectBuildTarget* target)
768
TiXmlElement* node = parentNode->FirstChildElement("LibDirs");
770
return; // no options
772
TiXmlElement* child = node->FirstChildElement("Add");
775
wxString option = cbC2U(child->Attribute("option"));
776
if (!option.IsEmpty())
779
target->AddLibDir(option);
781
m_pProject->AddLibDir(option);
784
child = child->NextSiblingElement("Add");
788
void ProjectLoader::DoExtraCommands(TiXmlElement* parentNode, ProjectBuildTarget* target)
790
TiXmlElement* node = parentNode->FirstChildElement("ExtraCommands");
793
CompileOptionsBase* base = target ? target : (CompileOptionsBase*)m_pProject;
794
TiXmlElement* child = node->FirstChildElement("Mode");
797
wxString mode = cbC2U(child->Attribute("after"));
798
if (mode == _T("always"))
799
base->SetAlwaysRunPostBuildSteps(true);
801
child = child->NextSiblingElement("Mode");
804
child = node->FirstChildElement("Add");
810
if (child->Attribute("before"))
811
before = cbC2U(child->Attribute("before"));
812
if (child->Attribute("after"))
813
after = cbC2U(child->Attribute("after"));
815
if (!before.IsEmpty())
816
base->AddCommandsBeforeBuild(before);
817
if (!after.IsEmpty())
818
base->AddCommandsAfterBuild(after);
820
child = child->NextSiblingElement("Add");
822
node = node->NextSiblingElement("ExtraCommands");
826
void ProjectLoader::DoEnvironment(TiXmlElement* parentNode, CompileOptionsBase* base)
830
TiXmlElement* node = parentNode->FirstChildElement("Environment");
833
TiXmlElement* child = node->FirstChildElement("Variable");
836
wxString name = cbC2U(child->Attribute("name"));
837
wxString value = cbC2U(child->Attribute("value"));
839
base->SetVar(name, UnixFilename(value));
841
child = child->NextSiblingElement("Variable");
843
node = node->NextSiblingElement("Environment");
847
void ProjectLoader::DoUnits(TiXmlElement* parentNode)
849
Manager::Get()->GetLogManager()->DebugLog(_T("Loading project files..."));
850
m_pProject->BeginAddFiles();
852
TiXmlElement* unit = parentNode->FirstChildElement("Unit");
855
wxString filename = cbC2U(unit->Attribute("filename"));
856
if (!filename.IsEmpty())
858
ProjectFile* file = m_pProject->AddFile(-1, UnixFilename(filename));
860
Manager::Get()->GetLogManager()->DebugLog(_T("Can't load file ") + filename);
864
DoUnitOptions(unit, file);
868
unit = unit->NextSiblingElement("Unit");
870
m_pProject->EndAddFiles();
871
Manager::Get()->GetLogManager()->DebugLog(F(_T("%d files loaded"), count));
874
void ProjectLoader::DoUnitOptions(TiXmlElement* parentNode, ProjectFile* file)
877
bool foundCompile = false;
878
bool foundLink = false;
879
bool foundCompilerVar = false;
880
bool foundTarget = false;
881
bool noTarget = false;
883
// Compiler* compiler = CompilerFactory::GetCompiler(m_pProject->GetCompilerID());
885
TiXmlElement* node = parentNode->FirstChildElement("Option");
888
if (node->Attribute("compilerVar"))
890
file->compilerVar = cbC2U(node->Attribute("compilerVar"));
891
foundCompilerVar = true;
894
if (node->QueryIntAttribute("compile", &tempval) == TIXML_SUCCESS)
896
file->compile = tempval != 0;
900
if (node->QueryIntAttribute("link", &tempval) == TIXML_SUCCESS)
902
file->link = tempval != 0;
906
if (node->QueryIntAttribute("weight", &tempval) == TIXML_SUCCESS)
907
file->weight = tempval;
909
if (node->Attribute("virtualFolder"))
911
file->virtual_path = UnixFilename(cbC2U(node->Attribute("virtualFolder")));
914
if (node->Attribute("buildCommand") && node->Attribute("compiler"))
916
wxString cmp = cbC2U(node->Attribute("compiler"));
917
wxString tmp = cbC2U(node->Attribute("buildCommand"));
918
if (!cmp.IsEmpty() && !tmp.IsEmpty())
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);
927
if (node->Attribute("target"))
929
wxString targetName = cbC2U(node->Attribute("target"));
930
if (!targetName.IsSameAs(_T("<{~None~}>")))
932
file->AddBuildTarget(targetName);
939
node = node->NextSiblingElement("Option");
942
// pre 1.6 versions upgrade
945
// make sure the "compile" and "link" flags are honored
947
file->compile = true;
950
if (!foundCompilerVar)
951
file->compilerVar = _T("CPP");
954
if (!foundTarget && !noTarget)
956
// add to all targets
957
for (int i = 0; i < m_pProject->GetBuildTargetsCount(); ++i)
959
file->AddBuildTarget(m_pProject->GetBuildTarget(i)->GetTitle());
962
// use same targets for generated files
963
for (size_t n = 0; n < file->generatedFiles.size(); ++n)
965
for (int i = 0; i < m_pProject->GetBuildTargetsCount(); ++i)
967
file->generatedFiles[n]->AddBuildTarget(m_pProject->GetBuildTarget(i)->GetTitle());
973
// convenience function, used in Save()
974
TiXmlElement* ProjectLoader::AddElement(TiXmlElement* parent, const char* name, const char* attr, const wxString& attribute)
976
TiXmlElement elem(name);
980
elem.SetAttribute(attr, cbU2C(attribute));
983
return parent->InsertEndChild(elem)->ToElement();
986
// convenience function, used in Save()
987
TiXmlElement* ProjectLoader::AddElement(TiXmlElement* parent, const char* name, const char* attr, int attribute)
989
TiXmlElement elem(name);
993
elem.SetAttribute(attr, attribute);
996
return parent->InsertEndChild(elem)->ToElement();
999
// convenience function, used in Save()
1000
void ProjectLoader::AddArrayOfElements(TiXmlElement* parent, const char* name, const char* attr, const wxArrayString& array)
1002
if (!array.GetCount())
1004
for (unsigned int i = 0; i < array.GetCount(); ++i)
1006
if (array[i].IsEmpty())
1008
AddElement(parent, name, attr, array[i]);
1012
// convenience function, used in Save()
1013
void ProjectLoader::SaveEnvironment(TiXmlElement* parent, CompileOptionsBase* base)
1017
const StringHash& v = base->GetAllVars();
1020
TiXmlElement* node = AddElement(parent, "Environment");
1021
for (StringHash::const_iterator it = v.begin(); it != v.end(); ++it)
1023
TiXmlElement* elem = AddElement(node, "Variable", "name", it->first);
1024
elem->SetAttribute("value", cbU2C(it->second));
1028
bool ProjectLoader::Save(const wxString& filename)
1030
return Save(filename, 0);
1033
bool ProjectLoader::Save(const wxString& filename, TiXmlElement* pExtensions)
1035
if (ExportTargetAsProject(filename, wxEmptyString, pExtensions))
1037
m_pProject->SetModified(false);
1043
bool ProjectLoader::ExportTargetAsProject(const wxString& filename, const wxString& onlyTarget, TiXmlElement* pExtensions)
1045
const char* ROOT_TAG = "CodeBlocks_project_file";
1048
doc.SetCondenseWhiteSpace(false);
1049
doc.InsertEndChild(TiXmlDeclaration("1.0", "UTF-8", "yes"));
1050
TiXmlElement* rootnode = static_cast<TiXmlElement*>(doc.InsertEndChild(TiXmlElement(ROOT_TAG)));
1054
// Compiler* compiler = CompilerFactory::GetCompiler(m_pProject->GetCompilerID());
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);
1060
rootnode->InsertEndChild(TiXmlElement("Project"));
1061
TiXmlElement* prjnode = rootnode->FirstChildElement("Project");
1063
AddElement(prjnode, "Option", "title", m_pProject->GetTitle());
1064
if (m_pProject->GetPlatforms() != spAll)
1066
wxString platforms = GetStringFromPlatforms(m_pProject->GetPlatforms());
1067
AddElement(prjnode, "Option", "platforms", platforms);
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())
1084
TiXmlElement* notesBase = AddElement(prjnode, "Option", "show_notes", m_pProject->GetShowNotesOnLoad() ? 1 : 0);
1085
if (!m_pProject->GetNotes().IsEmpty())
1087
TiXmlElement* notes = AddElement(notesBase, "notes");
1088
TiXmlText t(m_pProject->GetNotes().mb_str(wxConvUTF8));
1090
notes->InsertEndChild(t);
1094
if (m_pProject->MakeCommandsModified())
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));
1103
prjnode->InsertEndChild(TiXmlElement("Build"));
1104
TiXmlElement* buildnode = prjnode->FirstChildElement("Build");
1106
for (size_t x = 0; x < m_pProject->GetBuildScripts().GetCount(); ++x)
1108
AddElement(buildnode, "Script", "file", m_pProject->GetBuildScripts().Item(x));
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);
1115
for (int i = 0; i < m_pProject->GetBuildTargetsCount(); ++i)
1117
ProjectBuildTarget* target = m_pProject->GetBuildTarget(i);
1121
// skip every target except the desired one
1122
if (onlytgt && onlytgt != target)
1125
TiXmlElement* tgtnode = AddElement(buildnode, "Target", "title", target->GetTitle());
1126
if (target->GetPlatforms() != spAll)
1128
wxString platforms = GetStringFromPlatforms(target->GetPlatforms());
1129
AddElement(tgtnode, "Option", "platforms", platforms);
1131
if (target->GetTargetType() != ttCommandsOnly)
1133
TargetFilenameGenerationPolicy prefixPolicy;
1134
TargetFilenameGenerationPolicy extensionPolicy;
1135
target->GetTargetFilenameGenerationPolicy(prefixPolicy, extensionPolicy);
1137
wxString outputFileName = target->GetOutputFilename();
1138
if (extensionPolicy == tgfpPlatformDefault)
1140
wxFileName fname(outputFileName);
1142
outputFileName = fname.GetFullPath();
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");
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());
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));
1185
for (size_t x = 0; x < target->GetBuildScripts().GetCount(); ++x)
1187
AddElement(tgtnode, "Script", "file", target->GetBuildScripts().Item(x));
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);
1196
node = AddElement(tgtnode, "ResourceCompiler");
1197
AddArrayOfElements(node, "Add", "directory", target->GetResourceIncludeDirs());
1198
if (node->NoChildren())
1199
tgtnode->RemoveChild(node);
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);
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);
1215
if (target->GetAlwaysRunPostBuildSteps())
1216
AddElement(node, "Mode", "after", wxString(_T("always")));
1219
SaveEnvironment(tgtnode, target);
1221
if (target->MakeCommandsModified())
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));
1231
// virtuals only for whole project
1232
if (onlyTarget.IsEmpty())
1234
TiXmlElement* virtnode = AddElement(prjnode, "VirtualTargets");
1235
wxArrayString virtuals = m_pProject->GetVirtualBuildTargets();
1236
for (size_t i = 0; i < virtuals.GetCount(); ++i)
1238
const wxArrayString& group = m_pProject->GetVirtualBuildTargetGroup(virtuals[i]);
1239
wxString groupStr = GetStringFromArray(group, _T(";"));
1240
if (!groupStr.IsEmpty())
1242
TiXmlElement* elem = AddElement(virtnode, "Add", "alias", virtuals[i]);
1243
elem->SetAttribute("targets", cbU2C(groupStr));
1246
if (virtnode->NoChildren())
1247
prjnode->RemoveChild(virtnode);
1250
SaveEnvironment(buildnode, m_pProject);
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);
1258
node = AddElement(prjnode, "ResourceCompiler");
1259
AddArrayOfElements(node, "Add", "directory", m_pProject->GetResourceIncludeDirs());
1260
if (node->NoChildren())
1261
prjnode->RemoveChild(node);
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);
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);
1277
if (m_pProject->GetAlwaysRunPostBuildSteps())
1278
AddElement(node, "Mode", "after", wxString(_T("always")));
1281
int count = m_pProject->GetFilesCount();
1282
for (int i = 0; i < count; ++i)
1284
ProjectFile* f = m_pProject->GetFile(i);
1286
// do not save auto-generated files
1287
if (f->autoGeneratedBy)
1290
// do not save project files that do not belong in the target we 're exporting
1291
if (onlytgt && !onlytgt->GetFilesList().Find(f))
1294
FileType ft = FileTypeOf(f->relativeFilename);
1296
TiXmlElement* unitnode = AddElement(prjnode, "Unit", "filename", f->relativeFilename);
1297
if (!f->compilerVar.IsEmpty())
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);
1303
else if (f->compilerVar != _T("WINDRES") && ext.IsSameAs(FileFilters::RESOURCE_EXT))
1304
AddElement(unitnode, "Option", "compilerVar", f->compilerVar);
1306
else if (f->compilerVar != _T("CPP")) // default
1307
AddElement(unitnode, "Option", "compilerVar", f->compilerVar);
1310
if (f->compile != (ft == ftSource || ft == ftResource))
1312
AddElement(unitnode, "Option", "compile", f->compile ? 1 : 0);
1318
ft == ftResourceBin ||
1321
AddElement(unitnode, "Option", "link", f->link ? 1 : 0);
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);
1328
// loop and save custom build commands
1329
for (pfCustomBuildMap::iterator it = f->customBuild.begin(); it != f->customBuild.end(); ++it)
1331
pfCustomBuild& pfcb = it->second;
1332
if (!pfcb.buildCommand.IsEmpty())
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));
1342
if ((int)f->buildTargets.GetCount() != m_pProject->GetBuildTargetsCount())
1344
for (unsigned int x = 0; x < f->buildTargets.GetCount(); ++x)
1345
AddElement(unitnode, "Option", "target", f->buildTargets[x]);
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)
1352
AddElement(unitnode, "Option", "target", _T("<{~None~}>"));
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)
1362
ProjectLoaderHooks::CallHooks(m_pProject, extnode, false);
1365
return cbSaveTinyXMLDocument(&doc, filename);
1368
wxString ProjectLoader::GetValidCompilerID(const wxString& proposal, const wxString& scope)
1370
if (CompilerFactory::GetCompiler(proposal))
1373
// check the map; maybe we asked the user before
1374
CompilerSubstitutes::iterator it = m_CompilerSubstitutes.find(proposal);
1375
if (it != m_CompilerSubstitutes.end())
1378
Compiler* compiler = 0;
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())
1385
if (proposal.ToLong(&idx))
1386
compiler = CompilerFactory::GetCompiler(idx);
1391
if(!(Manager::Get()->GetConfigManager(_T("app"))->ReadBool(_T("/environment/ignore_invalid_targets"), false)))
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(),
1398
compiler = CompilerFactory::SelectCompilerUI(msg);
1404
// allow for invalid compiler IDs to be preserved...
1405
m_CompilerSubstitutes[proposal] = proposal;
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();