Code::Blocks  SVN r11506
compiler.cpp
Go to the documentation of this file.
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: https://svn.code.sf.net/p/codeblocks/code/trunk/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 
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 
47 
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;
61  libPrefix = _T("lib");
62  libExtension = _T("a");
63  linkerNeedsLibPrefix = 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 
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;
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 
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;
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 ;)
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];
135  m_LibDirs = MakeUniqueArray(other.m_LibDirs, true);
138  m_LinkLibs = other.m_LinkLibs;
139  m_CmdsBefore = other.m_CmdsBefore;
140  m_CmdsAfter = other.m_CmdsAfter;
141  m_RegExes = other.m_RegExes;
143  m_Weight = 100; // place copied compilers at the end
144 
145  for (int i = 0; i < ctCount; ++i)
147 
148  m_Valid = other.m_Valid;
150 }
151 
153 {
154  //dtor
155 }
156 
158 {
160  for (int i = 0; i < ctCount; ++i)
161  m_Commands[i].clear();
163 
165 
168  m_LinkLibs.Clear();
170  m_CmdsAfter.Clear();
171  SetVersionString(); // Does nothing unless reimplemented
172 }
173 
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
181 }
182 
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.
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 
201  {
202  m_Valid = false;
203  return false;
204  }
205 
206  wxString tmp = m_MasterPath + _T("/bin/") + m_Programs.C;
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.
234 {
236  return _("Compiler doesn't support this platform!\n");
237 
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 
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);
296 }
297 
299 {
301  generator->Init(project);
302  return generator;
303 }
304 
305 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 
334 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 
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;
373  for (int i = 0; i < ctCount; ++i)
374  m_Mirror.Commands[i] = m_Commands[i];
379 
388 
391 
392  m_Mirrored = true;
393 }
394 
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 
414  {
416  cfg->Write(tmp + _T("/compiler_options"), key, false);
417  }
419  {
421  cfg->Write(tmp + _T("/resource_compiler_options"), key, false);
422  }
424  {
426  cfg->Write(tmp + _T("/linker_options"), key, false);
427  }
429  {
431  cfg->Write(tmp + _T("/include_dirs"), key, false);
432  }
434  {
436  cfg->Write(tmp + _T("/res_include_dirs"), key, false);
437  }
438  if (m_Mirror.LibDirs != m_LibDirs)
439  {
441  cfg->Write(tmp + _T("/library_dirs"), key, false);
442  }
444  {
446  cfg->Write(tmp + _T("/libraries"), key, false);
447  }
449  {
451  cfg->Write(tmp + _T("/commands_before"), key, true);
452  }
454  {
456  cfg->Write(tmp + _T("/commands_after"), key, true);
457  }
458 
460  cfg->Write(tmp + _T("/master_path"), m_MasterPath, true);
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);
466  cfg->Write(tmp + _T("/cpp_compiler"), m_Programs.CPP, true);
468  cfg->Write(tmp + _T("/linker"), m_Programs.LD, true);
470  cfg->Write(tmp + _T("/lib_linker"), m_Programs.LIB, true);
472  cfg->Write(tmp + _T("/res_compiler"), m_Programs.WINDRES, true);
474  cfg->Write(tmp + _T("/make"), m_Programs.MAKE, true);
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
494  cfg->Write(tmp + _T("/switches/includes"), m_Switches.includeDirs, true);
496  cfg->Write(tmp + _T("/switches/libs"), m_Switches.libDirs, true);
498  cfg->Write(tmp + _T("/switches/link"), m_Switches.linkLibs, true);
500  cfg->Write(tmp + _T("/switches/define"), m_Switches.defines, true);
502  cfg->Write(tmp + _T("/switches/generic"), m_Switches.genericSwitch, true);
504  cfg->Write(tmp + _T("/switches/objectext"), m_Switches.objectExtension, true);
506  cfg->Write(tmp + _T("/switches/deps"), m_Switches.needDependencies);
508  cfg->Write(tmp + _T("/switches/forceCompilerQuotes"), m_Switches.forceCompilerUseQuotes);
510  cfg->Write(tmp + _T("/switches/forceLinkerQuotes"), m_Switches.forceLinkerUseQuotes);
512  cfg->Write(tmp + _T("/switches/logging"), m_Switches.logging);
514  cfg->Write(tmp + _T("/switches/libPrefix"), m_Switches.libPrefix, true);
516  cfg->Write(tmp + _T("/switches/libExtension"), m_Switches.libExtension, true);
518  cfg->Write(tmp + _T("/switches/linkerNeedsLibPrefix"), m_Switches.linkerNeedsLibPrefix);
520  cfg->Write(tmp + _T("/switches/linkerNeedsLibExtension"), m_Switches.linkerNeedsLibExtension);
522  cfg->Write(tmp + _T("/switches/linkerNeedsPathResolved"), m_Switches.linkerNeedsPathResolved);
524  cfg->Write(tmp + _T("/switches/forceFwdSlashes"), m_Switches.forceFwdSlashes);
526  cfg->Write(tmp + _T("/switches/supportsPCH"), m_Switches.supportsPCH);
528  cfg->Write(tmp + _T("/switches/pchExtension"), m_Switches.PCHExtension);
530  cfg->Write(tmp + _T("/switches/UseFlatObjects"), m_Switches.UseFlatObjects);
532  cfg->Write(tmp + _T("/switches/UseFullSourcePaths"), m_Switches.UseFullSourcePaths);
534  cfg->Write(tmp + _T("/switches/includeDirSeparator"), (int)m_Switches.includeDirSeparator);
536  cfg->Write(tmp + _T("/switches/libDirSeparator"), (int)m_Switches.libDirSeparator);
538  cfg->Write(tmp + _T("/switches/objectSeparator"), (int)m_Switches.objectSeparator);
540  cfg->Write(tmp + _T("/switches/statusSuccess"), m_Switches.statusSuccess);
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());
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 
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
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"),
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 
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" !!
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
763  {
764  for (int i = 0; i < ctCount; ++i)
765  m_Commands[i] = m_Mirror.Commands[i];
769  }
770  }
771 }
772 
774 {
776  {
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 &regex = 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 
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."));
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"))
940  else if (value == wxT("simple"))
942  else if (value == wxT("none"))
944  else
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))
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"));
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(" "));
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  {
1093  }
1094 }
1095 
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  {
1104  if (doc.IsEmpty())
1106  }
1107  else
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);
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 
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 
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 }
wxArrayString CmdsBefore
Definition: compiler.h:447
static wxString CommandTypeDescriptions[ctCount]
Get the command type descriptions (used in advanced compiler options)
Definition: compiler.h:356
RegExArray m_RegExes
Definition: compiler.h:415
bool linkerNeedsLibExtension
Definition: compiler.h:226
wxString F(const wxChar *msg,...)
sprintf-like function
Definition: logmanager.h:20
DLLIMPORT wxArrayString GetArrayFromString(const wxString &text, const wxString &separator=DEFAULT_ARRAY_SEP, bool trimSpaces=true)
Definition: globals.cpp:134
wxArrayString ExtraPaths
Definition: compiler.h:436
CompilerLoggingType logging
Definition: compiler.h:222
CompilerOptions Options
Definition: compiler.h:453
bool EvalXMLCondition(const wxXmlNode *node)
Definition: compiler.cpp:1179
wxArrayString generatedFiles
the native language files this command generates that should be further compiled
Definition: compiler.h:264
wxString PCHExtension
Definition: compiler.h:229
bool wxGetEnv(const wxString &var, wxString *value)
wxArrayString m_LinkLibs
CompilerPrograms Programs
Definition: compiler.h:437
#define wxICON_QUESTION
Data folder in user&#39;s dir.
Definition: configmanager.h:75
wxArrayString m_CmdsBefore
CompilerSwitches Switches
Definition: compiler.h:452
static wxArrayString m_CompilerIDs
Definition: compiler.h:427
virtual void SetResourceCompilerOptions(const wxArrayString &resourceCompilerOpts)
static const CompilerLoggingType defaultLogging
Definition: compiler.h:211
bool wxIsspace(const wxUniChar &c)
CompilerLoggingType
Helper enum for type of compiler logging.
Definition: compiler.h:183
const int version
Generate command-lines needed to produce a build.
ConfigManager * GetConfigManager(const wxString &name_space) const
Definition: manager.cpp:474
wxXmlNode * GetRoot() const
wxString genericSwitch
Definition: compiler.h:216
int ReadInt(const wxString &name, int defaultVal=0)
virtual bool SupportsCurrentPlatform() const
static Manager * Get()
Use Manager::Get() to get a pointer to its instance Manager::Get() is guaranteed to never return an i...
Definition: manager.cpp:182
wxString libDirs
Definition: compiler.h:213
bool m_Mirrored
Definition: compiler.h:459
wxString WINDRES
Definition: compiler.h:203
wxString m_Error
Definition: compiler.h:418
wxString Lower() const
bool GetAttribute(const wxString &attrName, wxString *value) const
#define wxICON_ERROR
virtual const CompilerTool * GetCompilerTool(CommandType ct, const wxString &fileExtension=wxEmptyString) const
Get a compiler tool based on CommandType.
Definition: compiler.cpp:334
bool wxFileExists(const wxString &filename)
void LogWarning(const wxString &msg, int i=app_log)
Definition: logmanager.h:141
virtual void SetLibDirs(const wxArrayString &libDirs)
Link console executable command, e.g. "$linker $libdirs -o $exe_output $link_objects $libs"...
Definition: compiler.h:172
bool m_MultiLineMessages
Definition: compiler.h:423
wxArrayString extensions
file extensions for which the command will be invoked (no leading dot)
Definition: compiler.h:263
bool ReadBool(const wxString &name, bool defaultVal=false)
Generate dependencies command.
Definition: compiler.h:169
wxArrayString m_ResIncludeDirs
wxString MakeInvalidCompilerMessages() const
Returns messages which might be useful to the use for debugging why the compiler is invalid...
Definition: compiler.cpp:233
wxString m_SortOptions[2]
Definition: compiler.h:420
wxString m_ErrorFilename
Definition: compiler.h:416
size_t Length() const
wxString CPP
Definition: compiler.h:200
wxArrayString CmdsAfter
Definition: compiler.h:448
wxCStrData c_str() const
bool Matches(const wxString &text, int flags=0) const
static int GetCompilerIndex(const wxString &id)
virtual void Reset()
Reset settings to defaults.
Definition: compiler.cpp:157
#define _T(string)
int filename
Definition: compiler.h:145
bool wxIsdigit(const wxUniChar &c)
#define wxYES_NO
virtual void ReloadOptions()
Reload option flags (for copied compilers).
Definition: compiler.cpp:174
DLLIMPORT wxString GetStringFromArray(const wxArrayString &array, const wxString &separator=DEFAULT_ARRAY_SEP, bool SeparatorAtEnd=true)
Definition: globals.cpp:122
wxXmlNode * GetParent() const
const wxString & GetCPPOnlyFlags()
Definition: compiler.h:376
Compile object command, e.g. "$compiler $options $includes -c $file -o $object".
Definition: compiler.h:168
#define wxICON_INFORMATION
CompilerPrograms m_Programs
Definition: compiler.h:412
void SetCPPOnlyFlags(const wxString &flags)
Definition: compiler.h:373
wxString & Remove(size_t pos)
bool UseFullSourcePaths
Definition: compiler.h:231
virtual void SetLinkLibs(const wxArrayString &linkLibs)
MirrorSettings m_Mirror
Definition: compiler.h:458
const wxString & GetName() const
#define wxT(string)
CompilerLineType lt
Definition: compiler.h:143
wxArrayString ReadArrayString(const wxString &name)
static wxDateTime UNow()
wxString m_Name
Definition: compiler.h:408
wxString defines
Definition: compiler.h:215
wxArrayString LinkLibs
Definition: compiler.h:446
static wxString LocateDataFile(const wxString &filename, int search_dirs=sdAllKnown)
Locate a file in an installation- and platform-independent way.
wxString LD
Definition: compiler.h:201
virtual const wxString & GetCommand(CommandType ct, const wxString &fileExtension=wxEmptyString) const
Get a command based on CommandType.
Definition: compiler.cpp:305
CompilerLineType
Enum categorizing compiler&#39;s output line as warning/error/info/normal.
Definition: compiler.h:66
bool forceFwdSlashes
Definition: compiler.h:218
#define wxICON_EXCLAMATION
CompilerToolsVector m_Commands[ctCount]
Definition: compiler.h:411
virtual void LoadSettings(const wxString &baseKey)
Load settings.
Definition: compiler.cpp:584
const wxString CompilerSettingsVersion
Definition: compiler.cpp:44
wxXmlNode * GetNext() const
virtual void SetCompilerOptions(const wxArrayString &compilerOpts)
virtual void Init(cbProject *project)
Initialize for use with the specified project.
wxUSE_UNICODE_dependent wxChar
wxArrayString m_CompilerOptions
const wxString & GetID() const
Get this compiler&#39;s unique ID.
Definition: compiler.h:351
void Write(const wxString &name, const wxString &value, bool ignoreEmpty=false)
DLLIMPORT wxString UnixFilename(const wxString &filename, wxPathFormat format=wxPATH_NATIVE)
Definition: globals.cpp:228
wxString m_ErrorLine
Definition: compiler.h:417
virtual bool IsValid()
Check if the compiler is actually valid (installed).
Definition: compiler.cpp:190
Represents a Code::Blocks project.
Definition: cbproject.h:96
const wxString & wxGetTranslation(const wxString &string, const wxString &domain=wxEmptyString)
const wxString & GetCOnlyFlags()
Definition: compiler.h:375
std::vector< CompilerTool > CompilerToolsVector
Definition: compiler.h:267
wxArrayString LibDirs
Definition: compiler.h:445
Link dynamic (dll) lib command, e.g. "$linker -shared -Wl,--output-def=$def_output -Wl...
Definition: compiler.h:173
wxString m_VersionString
Definition: compiler.h:419
Struct for compiler/linker commands.
Definition: compiler.h:249
wxArrayString ResIncludeDirs
Definition: compiler.h:444
wxArrayString EnumerateSubPaths(const wxString &path)
wxArrayString m_ResourceCompilerOptions
wxString objectExtension
Definition: compiler.h:217
bool Exists(const wxString &name)
wxArrayString m_LinkerOptions
wxString MAKE
Definition: compiler.h:204
size_t Replace(const wxString &strOld, const wxString &strNew, bool replaceAll=true)
bool m_NeedValidityCheck
Definition: compiler.h:429
void MakeValidID()
Definition: compiler.cpp:261
const wxString EmptyString
Definition: compiler.cpp:46
wxChar includeDirSeparator
Definition: compiler.h:240
static const wxString sep
bool GetMatch(size_t *start, size_t *len, size_t index=0) const
wxXmlNode * GetChildren() const
LogManager * GetLogManager() const
Definition: manager.cpp:439
wxString Read(const wxString &key, const wxString &defaultVal=wxEmptyString)
wxArrayString m_ExtraPaths
Definition: compiler.h:410
virtual void SetIncludeDirs(const wxArrayString &includeDirs)
wxString libExtension
Definition: compiler.h:224
bool IsEmpty() const
wxString GetExecName(const wxString &name)
Definition: compiler.cpp:1270
wxChar objectSeparator
Definition: compiler.h:242
wxString linkLibs
Definition: compiler.h:214
virtual void SetCommandsBeforeBuild(const wxArrayString &commands)
This is a base class for all classes needing compilation parameters.
static wxUniChar GetPathSeparator(wxPathFormat format=wxPATH_NATIVE)
wxString DBGconfig
Definition: compiler.h:205
const wxStringCharType * wx_str() const
void MirrorCurrentSettings()
Definition: compiler.cpp:360
Link executable command, e.g. "$linker $libdirs -o $exe_output $link_objects $libs -mwindows"...
Definition: compiler.h:171
wxString includeDirs
Definition: compiler.h:212
wxString wxEmptyString
wxString command
command to execute
Definition: compiler.h:262
DLLIMPORT wxArrayString MakeUniqueArray(const wxArrayString &array, bool caseSens)
Definition: globals.cpp:198
CompilerToolsVector Commands[ctCount]
Definition: compiler.h:451
virtual void LoadDefaultRegExArray(bool globalPrecedence=false)
Load the default (preset) array of regexes used in errors/warnings recognition.
Definition: compiler.cpp:183
MacrosManager * GetMacrosManager() const
Definition: manager.cpp:454
const wxString & _(const wxString &string)
wxString & Trim(bool fromRight=true)
void ReplaceMacros(wxString &buffer, ProjectBuildTarget *target=nullptr, bool subrequest=false)
wxArrayString LinkerOptions
Definition: compiler.h:442
wxArrayString ResourceCompilerOptions
Definition: compiler.h:441
int wxAtoi(const wxString &str)
bool HasRegEx() const
Definition: compiler.h:139
wxString m_ParentID
Definition: compiler.h:426
#define cbThrow(message)
Definition: cbexception.h:42
CommandType
Helper enum to retrieve compiler commands.
Definition: compiler.h:166
bool wxIsalnum(const wxUniChar &c)
CompilerOptions m_Options
Definition: compiler.h:414
Definition: id.h:15
void LoadRegExArray(const wxString &name, bool globalPrecedence=false, int recursion=0)
Definition: compiler.cpp:1096
bool ToLong(long *val, int base=10) const
Compile Win32 resources command, e.g. "$rescomp -i $file -J rc -o $resource_output -O coff $includes"...
Definition: compiler.h:170
Abstract base class for compilers.
Definition: compiler.h:274
virtual void SetLinkerOptions(const wxArrayString &linkerOpts)
wxString & Append(const char *psz)
wxString libPrefix
Definition: compiler.h:223
void DeleteSubPath(const wxString &strPath)
bool IsEmpty() const
void Clear()
virtual CompilerLineType CheckForWarningsAndErrors(const wxString &line)
Check if the supplied string is a compiler warning/error.
Definition: compiler.cpp:773
bool forceLinkerUseQuotes
Definition: compiler.h:219
void LoadDefaultOptions(const wxString &name, int recursion=0)
Definition: compiler.cpp:809
void AddOption(CompOption *coption, int index=-1)
virtual bool SetVar(const wxString &key, const wxString &value, bool onlyIfExists=false)
wxString C
Definition: compiler.h:199
void Log(const wxString &msg, int i=app_log, Logger::level lv=Logger::info)
Definition: logmanager.h:140
const wxString & GetParentID() const
Get this compiler&#39;s parent&#39;s unique ID.
Definition: compiler.h:353
void DebugLog(const wxString &msg, Logger::level lv=Logger::info)
Definition: logmanager.h:146
wxString m_MasterPath
Definition: compiler.h:409
wxChar libDirSeparator
Definition: compiler.h:241
wxString & Prepend(const wxString &str)
virtual void SetResourceIncludeDirs(const wxArrayString &resIncludeDirs)
wxArrayString IncludeDirs
Definition: compiler.h:443
DLLIMPORT wxString MakeUniqueString(const wxString &text, const wxString &separator=DEFAULT_ARRAY_SEP, bool caseSens=true)
Definition: globals.cpp:217
size_t Add(const wxString &str, size_t copies=1)
bool StartsWith(const wxString &prefix, wxString *rest=NULL) const
wxString GetRegExString() const
Definition: compiler.h:130
bool linkerNeedsLibPrefix
Definition: compiler.h:225
bool Compile(const wxString &pattern, int flags=wxRE_DEFAULT)
wxString SortOptions[2]
Definition: compiler.h:456
virtual void SaveSettings(const wxString &baseKey)
Save settings.
Definition: compiler.cpp:395
wxString LIB
Definition: compiler.h:202
size_t GetCount() const
virtual bool Load(const wxString &filename, const wxString &encoding="UTF-8", int flags=wxXMLDOC_NONE)
Link native binary command.
Definition: compiler.h:175
wxUniChar GetChar(size_t n) const
wxArrayString m_CmdsAfter
Link static lib command, e.g. "ar -r $output $link_objects\n\tranlib $static_output".
Definition: compiler.h:174
int m_Weight
Definition: compiler.h:422
Data folder in base dir.
Definition: configmanager.h:81
wxArrayString CompilerOptions_
Definition: compiler.h:440
bool m_Valid
Definition: compiler.h:428
const wxRegEx & GetRegEx() const
Definition: compiler.h:140
wxString desc
Definition: compiler.h:142
~Compiler() override
Definition: compiler.cpp:152
bool wxSetEnv(const wxString &var, const wxString &value)
int Printf(const wxString &pszFormat,...)
wxString Format(const wxString &format=wxDefaultDateTimeFormat, const TimeZone &tz=Local) const
virtual void SetVersionString()
Set the compiler version string.
Definition: compiler.h:362
virtual const StringHash & GetAllVars() const
wxArrayString EnumerateKeys(const wxString &path)
bool forceCompilerUseQuotes
Definition: compiler.h:220
Do NOT use.
Definition: compiler.h:177
wxArrayString m_IncludeDirs
bool IsUniqueID(const wxString &ID)
Definition: compiler.h:392
wxString GetNodeContent() const
virtual void UnsetAllVars()
virtual void SetCommandsAfterBuild(const wxArrayString &commands)
static wxString Format(const wxString &format,...)
wxString m_ID
Definition: compiler.h:425
bool needDependencies
Definition: compiler.h:221
DLLIMPORT int cbMessageBox(const wxString &message, const wxString &caption=wxEmptyString, int style=wxOK, wxWindow *parent=NULL, int x=-1, int y=-1)
wxMessageBox wrapper.
Definition: globals.cpp:1395
void SetCOnlyFlags(const wxString &flags)
Definition: compiler.h:372
bool linkerNeedsPathResolved
Definition: compiler.h:227
long wxExecute(const wxString &command, int flags=wxEXEC_ASYNC, wxProcess *callback=NULL, const wxExecuteEnv *env=NULL)
CompilerSwitches m_Switches
Definition: compiler.h:413
int msg[3]
Definition: compiler.h:144
virtual CompilerCommandGenerator * GetCommandGenerator(cbProject *project)
This is to be overridden, if compiler needs to alter the default command line generation.
Definition: compiler.cpp:298
bool UseFlatObjects
Definition: compiler.h:230
Compiler(const wxString &name, const wxString &ID, const wxString &parentID=wxEmptyString, int weight=50)
Definition: compiler.cpp:91