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: 11182 $
6 * $Id: compiler.cpp 11182 2017-09-29 23:33:53Z fuscated $
7 * $HeadURL: svn://svn.code.sf.net/p/codeblocks/code/branches/release-20.xx/src/sdk/compiler.cpp $
8 */
9
10 #include "sdk_precomp.h"
11
12 #ifndef CB_PRECOMP
13 #include "cbexception.h"
14 #include "compiler.h"
15 #include "manager.h"
16 #include "logmanager.h"
17 #include "configmanager.h"
18 #include "macrosmanager.h"
19 #include "globals.h"
20 #include "compilerfactory.h"
21
22 #include <wx/intl.h>
23 #include <wx/regex.h>
24 #endif
25
26 #include "compilercommandgenerator.h"
27 #include <wx/arrimpl.cpp>
28 #include <wx/filefn.h>
29 #include <wx/xml/xml.h>
30
31
32 // static
33 wxArrayString Compiler::m_CompilerIDs; // map to guarantee unique IDs
34
35 // common regex that can be used by the different compiler for matching compiler output
36 // it can be used in the patterns for warnings, errors, ...
37 // NOTE : it is an approximation (for example the ':' can appear anywhere and several times)
38 const wxString Compiler::FilePathWithSpaces = _T("[][{}() \t#%$~[:alnum:]&_:+/\\.-]+");
39
40 // version of compiler settings
41 // when this is different from what is saved in the config, a message appears
42 // to the user saying that default settings have changed and asks him if he wants to
43 // use his own settings or the new defaults
44 const wxString CompilerSettingsVersion = _T("0.0.3");
45
46 const wxString EmptyString;
47
CompilerSwitches()48 CompilerSwitches::CompilerSwitches()
49 { // default based upon gnu
50 includeDirs = _T("-I");
51 libDirs = _T("-L");
52 linkLibs = _T("-l");
53 defines = _T("-D");
54 genericSwitch = _T("-");
55 objectExtension = _T("o");
56 needDependencies = true;
57 forceFwdSlashes = false;
58 forceCompilerUseQuotes = false;
59 forceLinkerUseQuotes = false;
60 logging = defaultLogging;
61 libPrefix = _T("lib");
62 libExtension = _T("a");
63 linkerNeedsLibPrefix = false;
64 linkerNeedsLibExtension = false;
65 linkerNeedsPathResolved = false;
66 supportsPCH = true;
67 PCHExtension = _T("gch");
68 UseFlatObjects = false;
69 UseFullSourcePaths = false;
70 Use83Paths = false;
71 includeDirSeparator = _T(' ');
72 libDirSeparator = _T(' ');
73 objectSeparator = _T(' ');
74 statusSuccess = 0;
75 }
76
77 wxString Compiler::CommandTypeDescriptions[ctCount] =
78 {
79 // These are the strings that describe each CommandType enumerator...
80 // No need to say that it must have the same order as the enumerators!
81 _("Compile single file to object file"),
82 _("Generate dependencies for file"),
83 _("Compile Win32 resource file"),
84 _("Link object files to executable"),
85 _("Link object files to console executable"),
86 _("Link object files to dynamic library"),
87 _("Link object files to static library"),
88 _("Link object files to native executable")
89 };
90
Compiler(const wxString & name,const wxString & ID,const wxString & parentID,int weight)91 Compiler::Compiler(const wxString& name, const wxString& ID, const wxString& parentID, int weight) :
92 m_Name(name),
93 m_MultiLineMessages(false),
94 m_ID(ID.Lower()),
95 m_ParentID(parentID.Lower()),
96 m_Valid(false),
97 m_NeedValidityCheck(true),
98 m_Mirrored(false)
99 {
100 //ctor
101 MakeValidID();
102
103 m_Switches.supportsPCH = false;
104 m_Switches.forceFwdSlashes = false;
105 m_VersionString = wxEmptyString;
106 m_Weight = weight;
107 m_RegExes.reserve(100);
108 Manager::Get()->GetLogManager()->DebugLog(F(_T("Added compiler \"%s\""), m_Name.wx_str()));
109 }
110
Compiler(const Compiler & other)111 Compiler::Compiler(const Compiler& other) :
112 CompileOptionsBase(other),
113 m_ParentID(other.m_ParentID.IsEmpty() ? other.m_ID : other.m_ParentID),
114 m_Mirror(other.m_Mirror),
115 m_Mirrored(other.m_Mirrored)
116 {
117 m_Name = _("Copy of ") + other.m_Name;
118 m_MultiLineMessages = other.m_MultiLineMessages;
119 // generate unique ID
120 // note that this copy constructor is protected and can only be called
121 // by our friend CompilerFactory. It knows what it's doing ;)
122 wxDateTime now = wxDateTime::UNow();
123 m_ID = now.Format(_T("%c"), wxDateTime::CET);
124 MakeValidID();
125
126 m_MasterPath = other.m_MasterPath;
127 m_ExtraPaths = other.m_ExtraPaths;
128 m_Programs = other.m_Programs;
129 m_Switches = other.m_Switches;
130 m_Options = other.m_Options;
131 m_SortOptions[0] = other.m_SortOptions[0];
132 m_SortOptions[1] = other.m_SortOptions[1];
133 m_IncludeDirs = MakeUniqueArray(other.m_IncludeDirs, true);
134 m_ResIncludeDirs = MakeUniqueArray(other.m_ResIncludeDirs, true);
135 m_LibDirs = MakeUniqueArray(other.m_LibDirs, true);
136 m_CompilerOptions = other.m_CompilerOptions;
137 m_LinkerOptions = other.m_LinkerOptions;
138 m_LinkLibs = other.m_LinkLibs;
139 m_CmdsBefore = other.m_CmdsBefore;
140 m_CmdsAfter = other.m_CmdsAfter;
141 m_RegExes = other.m_RegExes;
142 m_VersionString = other.m_VersionString;
143 m_Weight = 100; // place copied compilers at the end
144
145 for (int i = 0; i < ctCount; ++i)
146 m_Commands[(CommandType)i] = other.m_Commands[(CommandType)i];
147
148 m_Valid = other.m_Valid;
149 m_NeedValidityCheck = other.m_NeedValidityCheck;
150 }
151
~Compiler()152 Compiler::~Compiler()
153 {
154 //dtor
155 }
156
Reset()157 void Compiler::Reset()
158 {
159 m_Options.ClearOptions();
160 for (int i = 0; i < ctCount; ++i)
161 m_Commands[i].clear();
162 LoadDefaultOptions(GetID());
163
164 LoadDefaultRegExArray();
165
166 m_CompilerOptions.Clear();
167 m_LinkerOptions.Clear();
168 m_LinkLibs.Clear();
169 m_CmdsBefore.Clear();
170 m_CmdsAfter.Clear();
171 SetVersionString(); // Does nothing unless reimplemented
172 }
173
ReloadOptions()174 void Compiler::ReloadOptions()
175 {
176 if (ConfigManager::LocateDataFile(wxT("compilers/options_") + GetID() + wxT(".xml"), sdDataUser | sdDataGlobal).IsEmpty())
177 return; // Do not clear if the options cannot be reloaded
178 m_Options.ClearOptions();
179 LoadDefaultOptions(GetID());
180 LoadDefaultRegExArray();
181 }
182
LoadDefaultRegExArray(bool globalPrecedence)183 void Compiler::LoadDefaultRegExArray(bool globalPrecedence)
184 {
185 m_RegExes.clear();
186 LoadRegExArray(GetID(), globalPrecedence);
187 }
188
189 // Keep in sync with the MakeInvalidCompilerMessages method.
IsValid()190 bool Compiler::IsValid()
191 {
192 if (!m_NeedValidityCheck)
193 return m_Valid;
194
195 if (m_MasterPath.IsEmpty())
196 return true; // still initializing, don't try to test now
197
198 m_NeedValidityCheck = false;
199
200 if (!SupportsCurrentPlatform())
201 {
202 m_Valid = false;
203 return false;
204 }
205
206 wxString tmp = m_MasterPath + _T("/bin/") + m_Programs.C;
207 MacrosManager *macros = Manager::Get()->GetMacrosManager();
208 macros->ReplaceMacros(tmp);
209 m_Valid = wxFileExists(tmp);
210 if (!m_Valid)
211 {
212 // and try without appending the 'bin'
213 tmp = m_MasterPath + _T("/") + m_Programs.C;
214 macros->ReplaceMacros(tmp);
215 m_Valid = wxFileExists(tmp);
216 }
217 if (!m_Valid)
218 {
219 // look in extra paths too
220 for (size_t i = 0; i < m_ExtraPaths.GetCount(); ++i)
221 {
222 tmp = m_ExtraPaths[i] + _T("/") + m_Programs.C;
223 macros->ReplaceMacros(tmp);
224 m_Valid = wxFileExists(tmp);
225 if (m_Valid)
226 break;
227 }
228 }
229 return m_Valid;
230 }
231
232 // Keep in sync with the IsValid method.
MakeInvalidCompilerMessages() const233 wxString Compiler::MakeInvalidCompilerMessages() const
234 {
235 if (!SupportsCurrentPlatform())
236 return _("Compiler doesn't support this platform!\n");
237
238 MacrosManager *macros = Manager::Get()->GetMacrosManager();
239
240 wxString triedPathsMsgs;
241 wxString tmp = m_MasterPath + _T("/bin/") + m_Programs.C;
242 macros->ReplaceMacros(tmp);
243 triedPathsMsgs += F(_T("Tried to run compiler executable '%s', but failed!\n"), tmp.wx_str());
244
245 // and try without appending the 'bin'
246 tmp = m_MasterPath + _T("/") + m_Programs.C;
247 macros->ReplaceMacros(tmp);
248
249 // look in extra paths too
250 for (size_t i = 0; i < m_ExtraPaths.GetCount(); ++i)
251 {
252 triedPathsMsgs += F(_T("Tried to run compiler executable '%s', but failed!\n"), tmp.wx_str());
253
254 tmp = m_ExtraPaths[i] + _T("/") + m_Programs.C;
255 macros->ReplaceMacros(tmp);
256 }
257
258 return triedPathsMsgs;
259 }
260
MakeValidID()261 void Compiler::MakeValidID()
262 {
263 // basically, make it XML-element compatible
264 // only allow a-z, 0-9, _, and -
265 // (it is already lowercase)
266 // any non-conformant character will be removed
267
268 wxString newID;
269 if (m_ID.IsEmpty())
270 m_ID = m_Name;
271
272 size_t pos = 0;
273 while (pos < m_ID.Length())
274 {
275 wxChar ch = m_ID[pos];
276 if (wxIsalnum(ch) || ch == _T('_') || ch == _T('-')) // valid character
277 newID.Append(ch);
278 else if (wxIsspace(ch)) // convert spaces to underscores
279 newID.Append(_T('_'));
280 ++pos;
281 }
282
283 // make sure it's not starting with a number or a '-'.
284 // if it is, prepend "cb"
285 if (wxIsdigit(newID.GetChar(0)) || newID.GetChar(0) == _T('-'))
286 newID.Prepend(_T("cb"));
287
288 if (newID.IsEmpty()) // empty? wtf?
289 cbThrow(_T("Can't create a valid compiler ID for ") + m_Name);
290 m_ID = newID.Lower();
291
292 // check for unique ID
293 if (!IsUniqueID(m_ID))
294 cbThrow(_T("Compiler ID already exists for ") + m_Name);
295 m_CompilerIDs.Add(m_ID);
296 }
297
GetCommandGenerator(cbProject * project)298 CompilerCommandGenerator* Compiler::GetCommandGenerator(cbProject* project)
299 {
300 CompilerCommandGenerator* generator = new CompilerCommandGenerator;
301 generator->Init(project);
302 return generator;
303 }
304
GetCommand(CommandType ct,const wxString & fileExtension) const305 const wxString& Compiler::GetCommand(CommandType ct, const wxString& fileExtension) const
306 {
307 const CompilerToolsVector& vec = m_Commands[ct];
308
309 // no command?
310 if (vec.empty())
311 return EmptyString;
312
313 size_t catchAll = 0;
314
315 if (!fileExtension.IsEmpty())
316 {
317 for (size_t i = 0; i < vec.size(); ++i)
318 {
319 if (vec[i].extensions.GetCount() == 0)
320 {
321 catchAll = i;
322 continue;
323 }
324 for (size_t n = 0; n < vec[i].extensions.GetCount(); ++n)
325 {
326 if (vec[i].extensions[n] == fileExtension)
327 return vec[i].command;
328 }
329 }
330 }
331 return vec[catchAll].command;
332 }
333
GetCompilerTool(CommandType ct,const wxString & fileExtension) const334 const CompilerTool* Compiler::GetCompilerTool(CommandType ct, const wxString& fileExtension) const
335 {
336 const CompilerToolsVector& vec = m_Commands[ct];
337 if (vec.empty())
338 return nullptr;
339
340 size_t catchAll = 0;
341 if (!fileExtension.IsEmpty())
342 {
343 for (size_t i = 0; i < vec.size(); ++i)
344 {
345 if (vec[i].extensions.GetCount() == 0)
346 {
347 catchAll = i;
348 continue;
349 }
350 for (size_t n = 0; n < vec[i].extensions.GetCount(); ++n)
351 {
352 if (vec[i].extensions[n] == fileExtension)
353 return &vec[i];
354 }
355 }
356 }
357 return &vec[catchAll];
358 }
359
MirrorCurrentSettings()360 void Compiler::MirrorCurrentSettings()
361 {
362 // run just once
363 if (m_Mirrored)
364 return;
365
366 // keep the current settings safe
367 // so we can compare them when saving: this way we can only save what's
368 // different from the defaults
369
370 m_Mirror.Name = m_Name;
371 m_Mirror.MasterPath = m_MasterPath;
372 m_Mirror.ExtraPaths = m_ExtraPaths;
373 for (int i = 0; i < ctCount; ++i)
374 m_Mirror.Commands[i] = m_Commands[i];
375 m_Mirror.Programs = m_Programs;
376 m_Mirror.Switches = m_Switches;
377 m_Mirror.Options = m_Options;
378 m_Mirror.RegExes = m_RegExes;
379
380 m_Mirror.CompilerOptions_ = m_CompilerOptions;
381 m_Mirror.LinkerOptions = m_LinkerOptions;
382 m_Mirror.IncludeDirs = MakeUniqueArray(m_IncludeDirs, true);
383 m_Mirror.ResIncludeDirs = MakeUniqueArray(m_ResIncludeDirs, true);
384 m_Mirror.LibDirs = MakeUniqueArray(m_LibDirs, true);
385 m_Mirror.LinkLibs = m_LinkLibs;
386 m_Mirror.CmdsBefore = m_CmdsBefore;
387 m_Mirror.CmdsAfter = m_CmdsAfter;
388
389 m_Mirror.SortOptions[0] = m_SortOptions[0];
390 m_Mirror.SortOptions[1] = m_SortOptions[1];
391
392 m_Mirrored = true;
393 }
394
SaveSettings(const wxString & baseKey)395 void Compiler::SaveSettings(const wxString& baseKey)
396 {
397 ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("compiler"));
398
399 // save settings version
400 cfg->Write(_T("settings_version"), CompilerSettingsVersion);
401
402 wxString tmp;
403
404 // delete old-style keys (using integer IDs)
405 tmp.Printf(_T("%s/set%3.3d"), baseKey.c_str(), CompilerFactory::GetCompilerIndex(this) + 1);
406 cfg->DeleteSubPath(tmp);
407
408 tmp.Printf(_T("%s/%s"), baseKey.c_str(), m_ID.c_str());
409
410 cfg->Write(tmp + _T("/name"), m_Name);
411 cfg->Write(tmp + _T("/parent"), m_ParentID, true);
412
413 if (m_Mirror.CompilerOptions_ != m_CompilerOptions)
414 {
415 wxString key = GetStringFromArray(m_CompilerOptions);
416 cfg->Write(tmp + _T("/compiler_options"), key, false);
417 }
418 if (m_Mirror.ResourceCompilerOptions != m_ResourceCompilerOptions)
419 {
420 wxString key = GetStringFromArray(m_ResourceCompilerOptions);
421 cfg->Write(tmp + _T("/resource_compiler_options"), key, false);
422 }
423 if (m_Mirror.LinkerOptions != m_LinkerOptions)
424 {
425 wxString key = GetStringFromArray(m_LinkerOptions);
426 cfg->Write(tmp + _T("/linker_options"), key, false);
427 }
428 if (m_Mirror.IncludeDirs != m_IncludeDirs)
429 {
430 wxString key = GetStringFromArray( MakeUniqueArray(m_IncludeDirs, true) );
431 cfg->Write(tmp + _T("/include_dirs"), key, false);
432 }
433 if (m_Mirror.ResIncludeDirs != m_ResIncludeDirs)
434 {
435 wxString key = GetStringFromArray( MakeUniqueArray(m_ResIncludeDirs, true) );
436 cfg->Write(tmp + _T("/res_include_dirs"), key, false);
437 }
438 if (m_Mirror.LibDirs != m_LibDirs)
439 {
440 wxString key = GetStringFromArray( MakeUniqueArray(m_LibDirs, true) );
441 cfg->Write(tmp + _T("/library_dirs"), key, false);
442 }
443 if (m_Mirror.LinkLibs != m_LinkLibs)
444 {
445 wxString key = GetStringFromArray(m_LinkLibs);
446 cfg->Write(tmp + _T("/libraries"), key, false);
447 }
448 if (m_Mirror.CmdsBefore != m_CmdsBefore)
449 {
450 wxString key = GetStringFromArray(m_CmdsBefore);
451 cfg->Write(tmp + _T("/commands_before"), key, true);
452 }
453 if (m_Mirror.CmdsAfter != m_CmdsAfter)
454 {
455 wxString key = GetStringFromArray(m_CmdsAfter);
456 cfg->Write(tmp + _T("/commands_after"), key, true);
457 }
458
459 if (m_Mirror.MasterPath != m_MasterPath)
460 cfg->Write(tmp + _T("/master_path"), m_MasterPath, true);
461 if (m_Mirror.ExtraPaths != m_ExtraPaths)
462 cfg->Write(tmp + _T("/extra_paths"), GetStringFromArray( MakeUniqueArray(m_ExtraPaths, true), _T(";") ), true);
463 if (m_Mirror.Programs.C != m_Programs.C)
464 cfg->Write(tmp + _T("/c_compiler"), m_Programs.C, true);
465 if (m_Mirror.Programs.CPP != m_Programs.CPP)
466 cfg->Write(tmp + _T("/cpp_compiler"), m_Programs.CPP, true);
467 if (m_Mirror.Programs.LD != m_Programs.LD)
468 cfg->Write(tmp + _T("/linker"), m_Programs.LD, true);
469 if (m_Mirror.Programs.LIB != m_Programs.LIB)
470 cfg->Write(tmp + _T("/lib_linker"), m_Programs.LIB, true);
471 if (m_Mirror.Programs.WINDRES != m_Programs.WINDRES)
472 cfg->Write(tmp + _T("/res_compiler"), m_Programs.WINDRES, true);
473 if (m_Mirror.Programs.MAKE != m_Programs.MAKE)
474 cfg->Write(tmp + _T("/make"), m_Programs.MAKE, true);
475 if (m_Mirror.Programs.DBGconfig != m_Programs.DBGconfig)
476 cfg->Write(tmp + _T("/debugger_config"), m_Programs.DBGconfig, true);
477
478 for (int i = 0; i < ctCount; ++i)
479 {
480 for (size_t n = 0; n < m_Commands[i].size(); ++n)
481 {
482 if (n >= m_Mirror.Commands[i].size() || m_Mirror.Commands[i][n] != m_Commands[i][n])
483 {
484 wxString key = wxString::Format(_T("%s/macros/%s/tool%lu/"), tmp.c_str(), CommandTypeDescriptions[i].c_str(), static_cast<unsigned long>(n));
485 cfg->Write(key + _T("command"), m_Commands[i][n].command);
486 cfg->Write(key + _T("extensions"), m_Commands[i][n].extensions);
487 cfg->Write(key + _T("generatedFiles"), m_Commands[i][n].generatedFiles);
488 }
489 }
490 }
491
492 // switches
493 if (m_Mirror.Switches.includeDirs != m_Switches.includeDirs)
494 cfg->Write(tmp + _T("/switches/includes"), m_Switches.includeDirs, true);
495 if (m_Mirror.Switches.libDirs != m_Switches.libDirs)
496 cfg->Write(tmp + _T("/switches/libs"), m_Switches.libDirs, true);
497 if (m_Mirror.Switches.linkLibs != m_Switches.linkLibs)
498 cfg->Write(tmp + _T("/switches/link"), m_Switches.linkLibs, true);
499 if (m_Mirror.Switches.defines != m_Switches.defines)
500 cfg->Write(tmp + _T("/switches/define"), m_Switches.defines, true);
501 if (m_Mirror.Switches.genericSwitch != m_Switches.genericSwitch)
502 cfg->Write(tmp + _T("/switches/generic"), m_Switches.genericSwitch, true);
503 if (m_Mirror.Switches.objectExtension != m_Switches.objectExtension)
504 cfg->Write(tmp + _T("/switches/objectext"), m_Switches.objectExtension, true);
505 if (m_Mirror.Switches.needDependencies != m_Switches.needDependencies)
506 cfg->Write(tmp + _T("/switches/deps"), m_Switches.needDependencies);
507 if (m_Mirror.Switches.forceCompilerUseQuotes != m_Switches.forceCompilerUseQuotes)
508 cfg->Write(tmp + _T("/switches/forceCompilerQuotes"), m_Switches.forceCompilerUseQuotes);
509 if (m_Mirror.Switches.forceLinkerUseQuotes != m_Switches.forceLinkerUseQuotes)
510 cfg->Write(tmp + _T("/switches/forceLinkerQuotes"), m_Switches.forceLinkerUseQuotes);
511 if (m_Mirror.Switches.logging != m_Switches.logging)
512 cfg->Write(tmp + _T("/switches/logging"), m_Switches.logging);
513 if (m_Mirror.Switches.libPrefix != m_Switches.libPrefix)
514 cfg->Write(tmp + _T("/switches/libPrefix"), m_Switches.libPrefix, true);
515 if (m_Mirror.Switches.libExtension != m_Switches.libExtension)
516 cfg->Write(tmp + _T("/switches/libExtension"), m_Switches.libExtension, true);
517 if (m_Mirror.Switches.linkerNeedsLibPrefix != m_Switches.linkerNeedsLibPrefix)
518 cfg->Write(tmp + _T("/switches/linkerNeedsLibPrefix"), m_Switches.linkerNeedsLibPrefix);
519 if (m_Mirror.Switches.linkerNeedsLibExtension != m_Switches.linkerNeedsLibExtension)
520 cfg->Write(tmp + _T("/switches/linkerNeedsLibExtension"), m_Switches.linkerNeedsLibExtension);
521 if (m_Mirror.Switches.linkerNeedsPathResolved != m_Switches.linkerNeedsPathResolved)
522 cfg->Write(tmp + _T("/switches/linkerNeedsPathResolved"), m_Switches.linkerNeedsPathResolved);
523 if (m_Mirror.Switches.forceFwdSlashes != m_Switches.forceFwdSlashes)
524 cfg->Write(tmp + _T("/switches/forceFwdSlashes"), m_Switches.forceFwdSlashes);
525 if (m_Mirror.Switches.supportsPCH != m_Switches.supportsPCH)
526 cfg->Write(tmp + _T("/switches/supportsPCH"), m_Switches.supportsPCH);
527 if (m_Mirror.Switches.PCHExtension != m_Switches.PCHExtension)
528 cfg->Write(tmp + _T("/switches/pchExtension"), m_Switches.PCHExtension);
529 if (m_Mirror.Switches.UseFlatObjects != m_Switches.UseFlatObjects)
530 cfg->Write(tmp + _T("/switches/UseFlatObjects"), m_Switches.UseFlatObjects);
531 if (m_Mirror.Switches.UseFullSourcePaths != m_Switches.UseFullSourcePaths)
532 cfg->Write(tmp + _T("/switches/UseFullSourcePaths"), m_Switches.UseFullSourcePaths);
533 if (m_Mirror.Switches.includeDirSeparator != m_Switches.includeDirSeparator)
534 cfg->Write(tmp + _T("/switches/includeDirSeparator"), (int)m_Switches.includeDirSeparator);
535 if (m_Mirror.Switches.libDirSeparator != m_Switches.libDirSeparator)
536 cfg->Write(tmp + _T("/switches/libDirSeparator"), (int)m_Switches.libDirSeparator);
537 if (m_Mirror.Switches.objectSeparator != m_Switches.objectSeparator)
538 cfg->Write(tmp + _T("/switches/objectSeparator"), (int)m_Switches.objectSeparator);
539 if (m_Mirror.Switches.statusSuccess != m_Switches.statusSuccess)
540 cfg->Write(tmp + _T("/switches/statusSuccess"), m_Switches.statusSuccess);
541 if (m_Mirror.Switches.Use83Paths != m_Switches.Use83Paths)
542 cfg->Write(tmp + _T("/switches/Use83Paths"), m_Switches.Use83Paths);
543
544 // regexes
545 cfg->DeleteSubPath(tmp + _T("/regex"));
546 wxString group;
547 for (size_t i = 0; i < m_RegExes.size(); ++i)
548 {
549 if (i < m_Mirror.RegExes.size() && m_Mirror.RegExes[i] == m_RegExes[i])
550 continue;
551
552 group.Printf(_T("%s/regex/re%3.3lu"), tmp.c_str(), static_cast<unsigned long>(i + 1));
553 RegExStruct& rs = m_RegExes[i];
554 cfg->Write(group + _T("/description"), rs.desc, true);
555 if (rs.lt != 0)
556 cfg->Write(group + _T("/type"), rs.lt);
557 cfg->Write(group + _T("/regex"), rs.GetRegExString(), true);
558 if (rs.msg[0] != 0)
559 cfg->Write(group + _T("/msg1"), rs.msg[0]);
560 if (rs.msg[1] != 0)
561 cfg->Write(group + _T("/msg2"), rs.msg[1]);
562 if (rs.msg[2] != 0)
563 cfg->Write(group + _T("/msg3"), rs.msg[2]);
564 if (rs.filename != 0)
565 cfg->Write(group + _T("/filename"), rs.filename);
566 if (rs.line != 0)
567 cfg->Write(group + _T("/line"), rs.line);
568 }
569
570 // sorted flags
571 if (m_Mirror.SortOptions[0] != GetCOnlyFlags())
572 cfg->Write(tmp + _T("/sort/C"), GetCOnlyFlags());
573 if (m_Mirror.SortOptions[1] != GetCPPOnlyFlags())
574 cfg->Write(tmp + _T("/sort/CPP"), GetCPPOnlyFlags());
575
576 // custom vars
577 wxString configpath = tmp + _T("/custom_variables/");
578 cfg->DeleteSubPath(configpath);
579 const StringHash& v = GetAllVars();
580 for (StringHash::const_iterator it = v.begin(); it != v.end(); ++it)
581 cfg->Write(configpath + it->first, it->second);
582 }
583
LoadSettings(const wxString & baseKey)584 void Compiler::LoadSettings(const wxString& baseKey)
585 {
586 // before loading any compiler settings, keep the current settings safe
587 // so we can compare them when saving: this way we can only save what's
588 // different from the defaults
589 MirrorCurrentSettings();
590
591 ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("compiler"));
592
593 // read settings version
594 wxString version = cfg->Read(_T("settings_version"));
595 bool versionMismatch = version != CompilerSettingsVersion;
596
597 wxString tmp;
598
599 // if using old-style keys (using integer IDs), notify user about the changes
600 static bool saidAboutCompilerIDs = false;
601 tmp.Printf(_T("%s/set%3.3d"), baseKey.c_str(), CompilerFactory::GetCompilerIndex(this) + 1);
602 if (cfg->Exists(tmp + _T("/name")))
603 {
604 if (!saidAboutCompilerIDs)
605 {
606 saidAboutCompilerIDs = true;
607 cbMessageBox(_("Compilers now use unique names instead of integer IDs.\n"
608 "Projects will be updated accordingly on load, mostly automatic."),
609 _("Information"),
610 wxICON_INFORMATION);
611 }
612 // at this point, we 'll be using the old style configuration to load settings
613 }
614 else // it's OK to use new style
615 tmp.Printf(_T("%s/%s"), baseKey.c_str(), m_ID.c_str());
616
617 if (!cfg->Exists(tmp + _T("/name")))
618 {
619 tmp.Replace(wxT("-"), wxEmptyString); // try again using previous id format
620 if (!cfg->Exists(tmp + _T("/name")))
621 return;
622 }
623
624 wxString sep = wxFileName::GetPathSeparator();
625
626 m_Name = cfg->Read(tmp + _T("/name"), m_Name);
627
628 m_MasterPath = cfg->Read(tmp + _T("/master_path"), m_MasterPath);
629 m_ExtraPaths = MakeUniqueArray(GetArrayFromString(cfg->Read(tmp + _T("/extra_paths"), _T("")), _T(";")), true);
630 m_Programs.C = cfg->Read(tmp + _T("/c_compiler"), m_Programs.C);
631 m_Programs.CPP = cfg->Read(tmp + _T("/cpp_compiler"), m_Programs.CPP);
632 m_Programs.LD = cfg->Read(tmp + _T("/linker"), m_Programs.LD);
633 m_Programs.LIB = cfg->Read(tmp + _T("/lib_linker"), m_Programs.LIB);
634 m_Programs.WINDRES = cfg->Read(tmp + _T("/res_compiler"), m_Programs.WINDRES);
635 m_Programs.MAKE = cfg->Read(tmp + _T("/make"), m_Programs.MAKE);
636 m_Programs.DBGconfig = cfg->Read(tmp + _T("/debugger_config"), m_Programs.DBGconfig);
637
638 // set member variable containing the version string with the configuration toolchain executables, not only
639 // with the default ones, otherwise we might have an empty version-string
640 // Some MinGW installations do not include "mingw32-gcc" !!
641 SetVersionString();
642
643 SetCompilerOptions (GetArrayFromString(cfg->Read(tmp + _T("/compiler_options"), wxEmptyString)));
644 SetResourceCompilerOptions(GetArrayFromString(cfg->Read(tmp + _T("/resource_compiler_options"), wxEmptyString)));
645 SetLinkerOptions (GetArrayFromString(cfg->Read(tmp + _T("/linker_options"), wxEmptyString)));
646 SetIncludeDirs (GetArrayFromString(cfg->Read(tmp + _T("/include_dirs"), wxEmptyString)));
647 SetResourceIncludeDirs(GetArrayFromString(cfg->Read(tmp + _T("/res_include_dirs"), wxEmptyString)));
648 SetLibDirs (GetArrayFromString(cfg->Read(tmp + _T("/library_dirs"), wxEmptyString)));
649 SetLinkLibs (GetArrayFromString(cfg->Read(tmp + _T("/libraries"), wxEmptyString)));
650 SetCommandsBeforeBuild(GetArrayFromString(cfg->Read(tmp + _T("/commands_before"), wxEmptyString)));
651 SetCommandsAfterBuild (GetArrayFromString(cfg->Read(tmp + _T("/commands_after"), wxEmptyString)));
652
653 for (int i = 0; i < ctCount; ++i)
654 {
655 wxArrayString keys = cfg->EnumerateSubPaths(tmp + _T("/macros/") + CommandTypeDescriptions[i]);
656 for (size_t n = 0; n < keys.size(); ++n)
657 {
658 unsigned long index = 0;
659 if (keys[n].Mid(4).ToULong(&index)) // skip 'tool'
660 {
661 while (index >= m_Commands[i].size())
662 m_Commands[i].push_back(CompilerTool());
663 CompilerTool& tool = m_Commands[i][index];
664
665 wxString key = wxString::Format(_T("%s/macros/%s/tool%lu/"), tmp.c_str(), CommandTypeDescriptions[i].c_str(), index);
666 tool.command = cfg->Read(key + _T("command"));
667 tool.extensions = cfg->ReadArrayString(key + _T("extensions"));
668 tool.generatedFiles = cfg->ReadArrayString(key + _T("generatedFiles"));
669 }
670 }
671 }
672
673 // switches
674 m_Switches.includeDirs = cfg->Read(tmp + _T("/switches/includes"), m_Switches.includeDirs);
675 m_Switches.libDirs = cfg->Read(tmp + _T("/switches/libs"), m_Switches.libDirs);
676 m_Switches.linkLibs = cfg->Read(tmp + _T("/switches/link"), m_Switches.linkLibs);
677 m_Switches.defines = cfg->Read(tmp + _T("/switches/define"), m_Switches.defines);
678 m_Switches.genericSwitch = cfg->Read(tmp + _T("/switches/generic"), m_Switches.genericSwitch);
679 m_Switches.objectExtension = cfg->Read(tmp + _T("/switches/objectext"), m_Switches.objectExtension);
680 m_Switches.needDependencies = cfg->ReadBool(tmp + _T("/switches/deps"), m_Switches.needDependencies);
681 m_Switches.forceCompilerUseQuotes = cfg->ReadBool(tmp + _T("/switches/forceCompilerQuotes"), m_Switches.forceCompilerUseQuotes);
682 m_Switches.forceLinkerUseQuotes = cfg->ReadBool(tmp + _T("/switches/forceLinkerQuotes"), m_Switches.forceLinkerUseQuotes);
683 m_Switches.logging = (CompilerLoggingType)cfg->ReadInt(tmp + _T("/switches/logging"), m_Switches.logging);
684 m_Switches.libPrefix = cfg->Read(tmp + _T("/switches/libPrefix"), m_Switches.libPrefix);
685 m_Switches.libExtension = cfg->Read(tmp + _T("/switches/libExtension"), m_Switches.libExtension);
686 m_Switches.linkerNeedsLibPrefix = cfg->ReadBool(tmp + _T("/switches/linkerNeedsLibPrefix"), m_Switches.linkerNeedsLibPrefix);
687 m_Switches.linkerNeedsLibExtension = cfg->ReadBool(tmp + _T("/switches/linkerNeedsLibExtension"), m_Switches.linkerNeedsLibExtension);
688 m_Switches.linkerNeedsPathResolved = cfg->ReadBool(tmp + _T("/switches/linkerNeedsPathResolved"), m_Switches.linkerNeedsPathResolved);
689 m_Switches.forceFwdSlashes = cfg->ReadBool(tmp + _T("/switches/forceFwdSlashes"), m_Switches.forceFwdSlashes);
690 m_Switches.supportsPCH = cfg->ReadBool(tmp + _T("/switches/supportsPCH"), m_Switches.supportsPCH);
691 m_Switches.PCHExtension = cfg->Read(tmp + _T("/switches/pchExtension"), m_Switches.PCHExtension);
692 m_Switches.UseFlatObjects = cfg->ReadBool(tmp + _T("/switches/UseFlatObjects"), m_Switches.UseFlatObjects);
693 m_Switches.UseFullSourcePaths = cfg->ReadBool(tmp + _T("/switches/UseFullSourcePaths"), m_Switches.UseFullSourcePaths);
694 m_Switches.Use83Paths = cfg->ReadBool(tmp + _T("/switches/Use83Paths"), m_Switches.Use83Paths);
695 m_Switches.includeDirSeparator = (wxChar)cfg->ReadInt(tmp + _T("/switches/includeDirSeparator"), (int)m_Switches.includeDirSeparator);
696 m_Switches.libDirSeparator = (wxChar)cfg->ReadInt(tmp + _T("/switches/libDirSeparator"), (int)m_Switches.libDirSeparator);
697 m_Switches.objectSeparator = (wxChar)cfg->ReadInt(tmp + _T("/switches/objectSeparator"), (int)m_Switches.objectSeparator);
698 m_Switches.statusSuccess = cfg->ReadInt(tmp + _T("/switches/statusSuccess"), m_Switches.statusSuccess);
699
700 // regexes
701
702 // because we 're only saving changed regexes, we can't just iterate like before.
703 // instead, we must iterate all child-keys and deduce the regex index number from
704 // the key name
705 wxArrayString keys = cfg->EnumerateSubPaths(tmp + _T("/regex/"));
706 wxString group;
707 long index = 0;
708 for (size_t i = 0; i < keys.GetCount(); ++i)
709 {
710 wxString key = keys[i];
711
712 // reNNN
713 if (!key.StartsWith(_T("re")))
714 continue;
715 key.Remove(0, 2);
716 if (!key.ToLong(&index, 10))
717 continue;
718
719 // 'index' now holds the regex index.
720 // read everything and either assign it to an existing regex
721 // if the index exists, or add a new regex
722
723 group.Printf(_T("%s/regex/re%3.3ld"), tmp.c_str(), index);
724 if (!cfg->Exists(group+_T("/description")))
725 continue;
726
727 RegExStruct rs(cfg->Read(group + _T("/description")),
728 (CompilerLineType)cfg->ReadInt(group + _T("/type"), 0),
729 cfg->Read(group + _T("/regex")),
730 cfg->ReadInt(group + _T("/msg1"), 0),
731 cfg->ReadInt(group + _T("/filename"), 0),
732 cfg->ReadInt(group + _T("/line"), 0),
733 cfg->ReadInt(group + _T("/msg2"), 0),
734 cfg->ReadInt(group + _T("/msg3"), 0));
735
736 if (index <= (long)m_RegExes.size())
737 m_RegExes[index - 1] = rs;
738 else
739 m_RegExes.push_back(rs);
740 }
741
742 // sorted flags
743 m_SortOptions[0] = cfg->Read(tmp + _T("/sort/C"), m_SortOptions[0]);
744 m_SortOptions[1] = cfg->Read(tmp + _T("/sort/CPP"), m_SortOptions[1]);
745
746 // custom vars
747 wxString configpath = tmp + _T("/custom_variables/");
748 UnsetAllVars();
749 wxArrayString list = cfg->EnumerateKeys(configpath);
750 for (unsigned int i = 0; i < list.GetCount(); ++i)
751 SetVar(list[i], cfg->Read(configpath + _T('/') + list[i]), false);
752
753 if (versionMismatch)
754 {
755 wxString msg;
756 msg << _("Some compiler settings defaults have changed in this version.\n"
757 "It is recommended that you allow updating of your settings to the new defaults.\n"
758 "Only disallow this if you don't want to lose any customizations you have done to this compiler's settings.\n\n"
759 "Note that the only settings that are affected are those found in \"Advanced compiler options\"...\n\n"
760 "Do you want to update your current settings to the new defaults?");
761 // don't ask if the compiler is not valid (i.e. not installed), just update
762 if (!IsValid() || cbMessageBox(msg, m_Name, wxICON_QUESTION | wxYES_NO) == wxID_YES)
763 {
764 for (int i = 0; i < ctCount; ++i)
765 m_Commands[i] = m_Mirror.Commands[i];
766 m_Switches = m_Mirror.Switches;
767 m_Options = m_Mirror.Options;
768 m_RegExes = m_Mirror.RegExes;
769 }
770 }
771 }
772
CheckForWarningsAndErrors(const wxString & line)773 CompilerLineType Compiler::CheckForWarningsAndErrors(const wxString& line)
774 {
775 if (!m_MultiLineMessages || (m_MultiLineMessages && !m_Error.IsEmpty()))
776 {
777 m_ErrorFilename.Clear();
778 m_ErrorLine.Clear();
779 m_Error.Clear();
780 }
781
782 for (size_t i = 0; i < m_RegExes.size(); ++i)
783 {
784 RegExStruct& rs = m_RegExes[i];
785 if (!rs.HasRegEx())
786 continue;
787 const wxRegEx ®ex = rs.GetRegEx();
788 if (regex.Matches(line))
789 {
790 if (rs.filename > 0)
791 m_ErrorFilename = UnixFilename(regex.GetMatch(line, rs.filename));
792 if (rs.line > 0)
793 m_ErrorLine = regex.GetMatch(line, rs.line);
794 for (int x = 0; x < 3; ++x)
795 {
796 if (rs.msg[x] > 0)
797 {
798 if (!m_Error.IsEmpty())
799 m_Error << _T(" ");
800 m_Error << regex.GetMatch(line, rs.msg[x]);
801 }
802 }
803 return rs.lt;
804 }
805 }
806 return cltNormal; // default return value
807 }
808
LoadDefaultOptions(const wxString & name,int recursion)809 void Compiler::LoadDefaultOptions(const wxString& name, int recursion)
810 {
811 wxXmlDocument options;
812 wxString doc = ConfigManager::LocateDataFile(wxT("compilers/options_") + name + wxT(".xml"), sdDataUser | sdDataGlobal);
813 if (doc.IsEmpty())
814 {
815 wxString msg(_("Error: file 'options_") + name + _(".xml' not found."));
816 Manager::Get()->GetLogManager()->Log(msg);
817 cbMessageBox(msg, _("Compiler options"), wxICON_ERROR);
818 return;
819 }
820 if (recursion > 5)
821 {
822 wxString msg(_("Warning: '") + doc + _("' not loaded due to excessive recursion."));
823 Manager::Get()->GetLogManager()->LogWarning(msg);
824 cbMessageBox(msg, _("Compiler options"), wxICON_EXCLAMATION);
825 return;
826 }
827 if (!options.Load(doc))
828 {
829 wxString msg(_("Error: Compiler options file '") + doc + _("' not found for compiler '") + name + wxT("'."));
830 Manager::Get()->GetLogManager()->Log(msg);
831 cbMessageBox(msg, _("Compiler options"), wxICON_ERROR);
832 return;
833 }
834 if (options.GetRoot()->GetName() != wxT("CodeBlocks_compiler_options"))
835 {
836 wxString msg(_("Error: Invalid Code::Blocks compiler options file for compiler '") + name + wxT("'."));
837 Manager::Get()->GetLogManager()->Log(msg);
838 cbMessageBox(msg, _("Compiler options"), wxICON_ERROR);
839 return;
840 }
841 wxString extends = options.GetRoot()->GetAttribute(wxT("extends"), wxEmptyString);
842 if (!extends.IsEmpty())
843 LoadDefaultOptions(extends, recursion + 1);
844 wxXmlNode* node = options.GetRoot()->GetChildren();
845 int depth = 0;
846 wxString categ;
847 bool exclu = false;
848
849 wxString baseKey = GetParentID().IsEmpty() ? wxT("/sets") : wxT("/user_sets");
850 ConfigManager* cfg = Manager::Get()->GetConfigManager(wxT("compiler"));
851 wxString cmpKey;
852 cmpKey.Printf(wxT("%s/set%3.3d"), baseKey.c_str(), CompilerFactory::GetCompilerIndex(this) + 1);
853 if (!cfg->Exists(cmpKey + wxT("/name")))
854 cmpKey.Printf(wxT("%s/%s"), baseKey.c_str(), m_ID.c_str());
855 if (!cfg->Exists(cmpKey + wxT("/name")))
856 cmpKey.Replace(wxT("-"), wxEmptyString);
857
858 while (node)
859 {
860 const wxString value = node->GetAttribute(wxT("value"), wxEmptyString);
861 if (node->GetName() == wxT("if") && node->GetChildren())
862 {
863 if (EvalXMLCondition(node))
864 {
865 node = node->GetChildren();
866 ++depth;
867 continue;
868 }
869 else if (node->GetNext() && node->GetNext()->GetName() == wxT("else") &&
870 node->GetNext()->GetChildren())
871 {
872 node = node->GetNext()->GetChildren();
873 ++depth;
874 continue;
875 }
876 }
877 else if (node->GetName() == wxT("Program")) // configuration is read so execution of renamed programs work, m_Mirror is needed to reset before leaving this function
878 {
879 wxString prog = node->GetAttribute(wxT("name"), wxEmptyString);
880 if (prog == wxT("C"))
881 {
882 m_Programs.C = cfg->Read(cmpKey + wxT("/c_compiler"), value);
883 m_Mirror.Programs.C = value;
884 }
885 else if (prog == wxT("CPP"))
886 {
887 m_Programs.CPP = cfg->Read(cmpKey + wxT("/cpp_compiler"), value);
888 m_Mirror.Programs.CPP = value;
889 }
890 else if (prog == wxT("LD"))
891 {
892 m_Programs.LD = cfg->Read(cmpKey + wxT("/linker"), value);
893 m_Mirror.Programs.LD = value;
894 }
895 else if (prog == wxT("DBGconfig"))
896 m_Programs.DBGconfig = value;
897 else if (prog == wxT("LIB"))
898 {
899 m_Programs.LIB = cfg->Read(cmpKey + wxT("/lib_linker"), value);
900 m_Mirror.Programs.LIB = value;
901 }
902 else if (prog == wxT("WINDRES"))
903 {
904 m_Programs.WINDRES = cfg->Read(cmpKey + wxT("/res_compiler"), value);
905 m_Mirror.Programs.WINDRES = value;
906 }
907 else if (prog == wxT("MAKE"))
908 {
909 m_Programs.MAKE = cfg->Read(cmpKey + wxT("/make"), value);
910 m_Mirror.Programs.MAKE = value;
911 }
912 }
913 else if (node->GetName() == wxT("Switch"))
914 {
915 wxString swi = node->GetAttribute(wxT("name"), wxEmptyString);
916 if (swi == wxT("includeDirs"))
917 m_Switches.includeDirs = value;
918 else if (swi == wxT("libDirs"))
919 m_Switches.libDirs = value;
920 else if (swi == wxT("linkLibs"))
921 m_Switches.linkLibs = value;
922 else if (swi == wxT("defines"))
923 m_Switches.defines = value;
924 else if (swi == wxT("genericSwitch"))
925 m_Switches.genericSwitch = value;
926 else if (swi == wxT("objectExtension"))
927 m_Switches.objectExtension = value;
928 else if (swi == wxT("forceFwdSlashes"))
929 m_Switches.forceFwdSlashes = (value == wxT("true"));
930 else if (swi == wxT("forceLinkerUseQuotes"))
931 m_Switches.forceLinkerUseQuotes = (value == wxT("true"));
932 else if (swi == wxT("forceCompilerUseQuotes"))
933 m_Switches.forceCompilerUseQuotes = (value == wxT("true"));
934 else if (swi == wxT("needDependencies"))
935 m_Switches.needDependencies = (value == wxT("true"));
936 else if (swi == wxT("logging"))
937 {
938 if (value == wxT("full"))
939 m_Switches.logging = clogFull;
940 else if (value == wxT("simple"))
941 m_Switches.logging = clogSimple;
942 else if (value == wxT("none"))
943 m_Switches.logging = clogNone;
944 else
945 m_Switches.logging = CompilerSwitches::defaultLogging;
946 }
947 else if (swi == wxT("libPrefix"))
948 m_Switches.libPrefix = value;
949 else if (swi == wxT("libExtension"))
950 m_Switches.libExtension = value;
951 else if (swi == wxT("linkerNeedsLibPrefix"))
952 m_Switches.linkerNeedsLibPrefix = (value == wxT("true"));
953 else if (swi == wxT("linkerNeedsLibExtension"))
954 m_Switches.linkerNeedsLibExtension = (value == wxT("true"));
955 else if (swi == wxT("linkerNeedsPathResolved"))
956 m_Switches.linkerNeedsPathResolved = (value == wxT("true"));
957 else if (swi == wxT("supportsPCH"))
958 m_Switches.supportsPCH = (value == wxT("true"));
959 else if (swi == wxT("PCHExtension"))
960 m_Switches.PCHExtension = value;
961 else if (swi == wxT("UseFlatObjects"))
962 m_Switches.UseFlatObjects = (value == wxT("true"));
963 else if (swi == wxT("UseFullSourcePaths"))
964 m_Switches.UseFullSourcePaths = (value == wxT("true"));
965 else if (swi == wxT("includeDirSeparator") && !value.IsEmpty())
966 m_Switches.includeDirSeparator = value[0];
967 else if (swi == wxT("libDirSeparator") && !value.IsEmpty())
968 m_Switches.libDirSeparator = value[0];
969 else if (swi == wxT("objectSeparator") && !value.IsEmpty())
970 m_Switches.objectSeparator = value[0];
971 else if (swi == wxT("statusSuccess") && !value.IsEmpty())
972 {
973 long val;
974 if (value.ToLong(&val))
975 m_Switches.statusSuccess = val;
976 }
977 else if (swi == wxT("Use83Paths"))
978 m_Switches.Use83Paths = (value == wxT("true"));
979 }
980 else if (node->GetName() == wxT("Category") && node->GetChildren())
981 {
982 categ = node->GetAttribute(wxT("name"), wxEmptyString);
983 exclu = (node->GetAttribute(wxT("exclusive"), wxEmptyString) == wxT("true"));
984 node = node->GetChildren();
985 ++depth;
986 continue;
987 }
988 else if (node->GetName() == wxT("Option"))
989 {
990 wxString category;
991 if (!node->GetAttribute(wxT("category"), &category))
992 {
993 if (categ.IsEmpty())
994 category = wxT("General");
995 else
996 category = categ;
997 }
998 wxString exclusive;
999 if (!node->GetAttribute(wxT("exclusive"), &exclusive))
1000 exclusive = (exclu ? wxT("true") : wxT("false"));
1001 m_Options.AddOption(wxGetTranslation(node->GetAttribute(wxT("name"), wxEmptyString)),
1002 node->GetAttribute(wxT("option"), wxEmptyString),
1003 wxGetTranslation(category),
1004 node->GetAttribute(wxT("additionalLibs"), wxEmptyString),
1005 node->GetAttribute(wxT("checkAgainst"), wxEmptyString),
1006 wxGetTranslation(node->GetAttribute(wxT("checkMessage"), wxEmptyString)),
1007 node->GetAttribute(wxT("supersedes"), wxEmptyString),
1008 exclusive == wxT("true"));
1009 }
1010 else if (node->GetName() == wxT("Command"))
1011 {
1012 wxString cmd = node->GetAttribute(wxT("name"), wxEmptyString);
1013 wxString unEscape = value;
1014 unEscape.Replace(wxT("\\n"), wxT("\n")); // a single tool can support multiple commands
1015 CompilerTool tool(unEscape, node->GetAttribute(wxT("ext"), wxEmptyString),
1016 node->GetAttribute(wxT("gen"), wxEmptyString));
1017 CommandType cmdTp = ctCount;
1018 if (cmd == wxT("CompileObject"))
1019 cmdTp = ctCompileObjectCmd;
1020 else if (cmd == wxT("GenDependencies"))
1021 cmdTp = ctGenDependenciesCmd;
1022 else if (cmd == wxT("CompileResource"))
1023 cmdTp = ctCompileResourceCmd;
1024 else if (cmd == wxT("LinkExe"))
1025 cmdTp = ctLinkExeCmd;
1026 else if (cmd == wxT("LinkConsoleExe"))
1027 cmdTp = ctLinkConsoleExeCmd;
1028 else if (cmd == wxT("LinkDynamic"))
1029 cmdTp = ctLinkDynamicCmd;
1030 else if (cmd == wxT("LinkStatic"))
1031 cmdTp = ctLinkStaticCmd;
1032 else if (cmd == wxT("LinkNative"))
1033 cmdTp = ctLinkNativeCmd;
1034 if (cmdTp != ctCount)
1035 {
1036 bool assigned = false;
1037 CompilerToolsVector& tools = m_Commands[cmdTp];
1038 for (size_t i = 0; i < tools.size(); ++i)
1039 {
1040 if (tools[i].extensions == tool.extensions)
1041 {
1042 tools[i] = tool;
1043 assigned = true;
1044 break;
1045 }
1046 }
1047 if (!assigned)
1048 tools.push_back(tool);
1049 }
1050 }
1051 else if (node->GetName() == wxT("Sort"))
1052 {
1053 wxString flags;
1054 if (node->GetAttribute(wxT("CFlags"), &flags))
1055 {
1056 flags.Replace(wxT("\n"), wxT(" "));
1057 flags.Replace(wxT("\r"), wxT(" "));
1058 SetCOnlyFlags( MakeUniqueString(GetCOnlyFlags() + wxT(" ") + flags,
1059 wxT(" ")) );
1060 }
1061 else if (node->GetAttribute(wxT("CPPFlags"), &flags))
1062 {
1063 flags.Replace(wxT("\n"), wxT(" "));
1064 flags.Replace(wxT("\r"), wxT(" "));
1065 SetCPPOnlyFlags( MakeUniqueString(GetCPPOnlyFlags() + wxT(" ") + flags,
1066 wxT(" ")) );
1067 }
1068 }
1069 else if (node->GetName() == wxT("Common"))
1070 {
1071 LoadDefaultOptions(wxT("common_") + node->GetAttribute(wxT("name"), wxEmptyString), recursion + 1);
1072 }
1073 while (!node->GetNext() && depth > 0)
1074 {
1075 node = node->GetParent();
1076 if (node->GetName() == wxT("Category"))
1077 {
1078 categ = wxEmptyString;
1079 exclu = false;
1080 }
1081 --depth;
1082 }
1083 node = node->GetNext();
1084 }
1085 if (recursion == 0) // reset programs to their actual defaults (customized settings are loaded in a different function)
1086 {
1087 m_Programs.C = m_Mirror.Programs.C;
1088 m_Programs.CPP = m_Mirror.Programs.CPP;
1089 m_Programs.LD = m_Mirror.Programs.LD;
1090 m_Programs.LIB = m_Mirror.Programs.LIB;
1091 m_Programs.WINDRES = m_Mirror.Programs.WINDRES;
1092 m_Programs.MAKE = m_Mirror.Programs.MAKE;
1093 }
1094 }
1095
LoadRegExArray(const wxString & name,bool globalPrecedence,int recursion)1096 void Compiler::LoadRegExArray(const wxString& name, bool globalPrecedence, int recursion)
1097 {
1098 wxXmlDocument options;
1099 wxString doc;
1100 const wxString fn = wxT("compilers/options_") + name + wxT(".xml");
1101 if (globalPrecedence)
1102 {
1103 doc = ConfigManager::LocateDataFile(fn, sdDataGlobal);
1104 if (doc.IsEmpty())
1105 doc = ConfigManager::LocateDataFile(fn, sdDataUser);
1106 }
1107 else
1108 doc = ConfigManager::LocateDataFile(fn, sdDataUser | sdDataGlobal);
1109 if (doc.IsEmpty())
1110 {
1111 Manager::Get()->GetLogManager()->Log(_("Error: file 'options_") + name + _(".xml' not found"));
1112 return;
1113 }
1114 if (recursion > 5)
1115 {
1116 Manager::Get()->GetLogManager()->LogWarning(_("Warning: '") + doc + _("' not loaded due to excessive recursion"));
1117 return;
1118 }
1119 if (!options.Load(doc))
1120 {
1121 Manager::Get()->GetLogManager()->Log(_("Error parsing ") + doc);
1122 return;
1123 }
1124 wxString extends = options.GetRoot()->GetAttribute(wxT("extends"), wxEmptyString);
1125 if (!extends.IsEmpty())
1126 LoadRegExArray(extends, globalPrecedence, recursion + 1);
1127 wxXmlNode* node = options.GetRoot()->GetChildren();
1128 int depth = 0;
1129 while (node)
1130 {
1131 const wxString value = node->GetAttribute(wxT("value"), wxEmptyString);
1132 if (node->GetName() == wxT("if") && node->GetChildren())
1133 {
1134 if (EvalXMLCondition(node))
1135 {
1136 node = node->GetChildren();
1137 ++depth;
1138 continue;
1139 }
1140 else if (node->GetNext() && node->GetNext()->GetName() == wxT("else") &&
1141 node->GetNext()->GetChildren())
1142 {
1143 node = node->GetNext()->GetChildren();
1144 ++depth;
1145 continue;
1146 }
1147 }
1148 else if (node->GetName() == wxT("RegEx"))
1149 {
1150 wxString tp = node->GetAttribute(wxT("type"), wxEmptyString);
1151 CompilerLineType clt = cltNormal;
1152 if (tp == wxT("warning"))
1153 clt = cltWarning;
1154 else if (tp == wxT("error"))
1155 clt = cltError;
1156 else if (tp == wxT("info"))
1157 clt = cltInfo;
1158 wxArrayString msg = GetArrayFromString(node->GetAttribute(wxT("msg"), wxEmptyString) + wxT(";0;0"));
1159 m_RegExes.push_back(RegExStruct(wxGetTranslation(node->GetAttribute(wxT("name"), wxEmptyString)), clt,
1160 node->GetNodeContent().Trim().Trim(false), wxAtoi(msg[0]),
1161 wxAtoi(node->GetAttribute(wxT("file"), wxT("0"))),
1162 wxAtoi(node->GetAttribute(wxT("line"), wxT("0"))),
1163 wxAtoi(msg[1]), wxAtoi(msg[2]) ) );
1164 }
1165 else if (node->GetName() == wxT("Common"))
1166 {
1167 LoadRegExArray(wxT("common_") + node->GetAttribute(wxT("name"), wxEmptyString),
1168 globalPrecedence, recursion + 1);
1169 }
1170 while (!node->GetNext() && depth > 0)
1171 {
1172 node = node->GetParent();
1173 --depth;
1174 }
1175 node = node->GetNext();
1176 }
1177 }
1178
EvalXMLCondition(const wxXmlNode * node)1179 bool Compiler::EvalXMLCondition(const wxXmlNode* node)
1180 {
1181 bool val = false;
1182 wxString test;
1183 if (node->GetAttribute(wxT("platform"), &test))
1184 {
1185 if (test == wxT("windows"))
1186 val = platform::windows;
1187 else if (test == wxT("macosx"))
1188 val = platform::macosx;
1189 else if (test == wxT("linux"))
1190 val = platform::Linux;
1191 else if (test == wxT("freebsd"))
1192 val = platform::freebsd;
1193 else if (test == wxT("netbsd"))
1194 val = platform::netbsd;
1195 else if (test == wxT("openbsd"))
1196 val = platform::openbsd;
1197 else if (test == wxT("darwin"))
1198 val = platform::darwin;
1199 else if (test == wxT("solaris"))
1200 val = platform::solaris;
1201 else if (test == wxT("unix"))
1202 val = platform::Unix;
1203 }
1204 else if (node->GetAttribute(wxT("exec"), &test))
1205 {
1206 wxArrayString cmd = GetArrayFromString(test, wxT(" "));
1207 if (cmd.IsEmpty())
1208 return false;
1209 wxString path;
1210 wxGetEnv(wxT("PATH"), &path);
1211 const wxString origPath = path;
1212 {
1213 ConfigManager* cfg = Manager::Get()->GetConfigManager(wxT("compiler"));
1214 wxString masterPath;
1215 wxString loc = (m_ParentID.IsEmpty() ? wxT("/sets/") : wxT("/user_sets/")) + m_ID;
1216 wxArrayString extraPaths;
1217 if (cfg->Exists(loc + wxT("/name")))
1218 {
1219 masterPath = cfg->Read(loc + wxT("/master_path"), wxEmptyString);
1220 extraPaths = MakeUniqueArray(GetArrayFromString(cfg->Read(loc + wxT("/extra_paths"), wxEmptyString)), true);
1221 }
1222 for (size_t i = 0; i < extraPaths.GetCount(); ++i)
1223 path.Prepend(extraPaths[i] + wxPATH_SEP);
1224 if (!masterPath.IsEmpty())
1225 path.Prepend(masterPath + wxPATH_SEP + masterPath + wxFILE_SEP_PATH + wxT("bin") + wxPATH_SEP);
1226 }
1227 wxSetEnv(wxT("PATH"), path);
1228 cmd[0] = GetExecName(cmd[0]);
1229
1230 long ret = -1;
1231 if ( !cmd[0].IsEmpty() ) // should never be empty
1232 {
1233 int flags = wxEXEC_SYNC;
1234 #if wxCHECK_VERSION(3, 0, 0)
1235 // Stop event-loop while wxExecute runs, to avoid a deadlock on startup,
1236 // that occurs from time to time on wx3
1237 flags |= wxEXEC_NOEVENTS;
1238 #else
1239 flags |= wxEXEC_NODISABLE;
1240 #endif
1241 wxLogNull logNo; // do not warn if execution fails
1242 ret = wxExecute(GetStringFromArray(cmd, wxT(" "), false), cmd, flags);
1243 }
1244
1245 if (ret != 0) // execution failed
1246 val = (node->GetAttribute(wxT("default"), wxEmptyString) == wxT("true"));
1247 else if (node->GetAttribute(wxT("regex"), &test))
1248 {
1249 wxRegEx re;
1250 if (re.Compile(test))
1251 {
1252 for (size_t i = 0; i < cmd.GetCount(); ++i)
1253 {
1254 if (re.Matches(cmd[i]))
1255 {
1256 val = true;
1257 break;
1258 }
1259 }
1260 }
1261 }
1262 else // execution succeeded (and no regex test given)
1263 val = true;
1264
1265 wxSetEnv(wxT("PATH"), origPath); // restore path
1266 }
1267 return val;
1268 }
1269
GetExecName(const wxString & name)1270 wxString Compiler::GetExecName(const wxString& name)
1271 {
1272 wxString ret = name;
1273 if (name == wxT("C"))
1274 ret = m_Programs.C;
1275 else if (name == wxT("CPP"))
1276 ret = m_Programs.CPP;
1277 else if (name == wxT("LD"))
1278 ret = m_Programs.LD;
1279 else if (name == wxT("LIB"))
1280 ret = m_Programs.LIB;
1281 else if (name == wxT("WINDRES"))
1282 ret = m_Programs.WINDRES;
1283 else if (name == wxT("MAKE"))
1284 ret = m_Programs.MAKE;
1285 return ret;
1286 }
1287