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 
6 #ifndef COMPILER_H
7 #define COMPILER_H
8 
9 #include <vector>
10 #include <map>
11 
12 #include <wx/string.h>
13 #include <wx/filename.h>
14 #include <wx/dynarray.h>
15 #include <wx/regex.h>
16 #include "compileoptionsbase.h"
17 #include "compileroptions.h"
18 
19 class CompilerCommandGenerator;
20 class cbProject;
21 class ProjectBuildTarget;
22 class ProjectFile;
23 class wxXmlNode;
24 
25 /*
26     Macros used in command specs:
27     (keep in sync with `src/plugins/compilergcc/resources/advanced_compiler_options.xrc`)
28 
29     Compiler executable: $compiler
30     Resource compiler executable: $rescomp
31     Linker executable: $linker
32     Linker executable for static libs: $lib_linker
33     Compiler flags: $options
34     Resource compiler flags: $res_options
35     Linker flags: $link_options
36     Compiler include paths: $includes
37     Resource include paths: $res_includes
38     Linker include paths: $libdirs
39     Link libraries: $libs
40     Source file (full name): $file
41     Source file dir (no name, no ext.): $file_dir
42     Source file name (no path, no ext.): $file_name
43     Source file extension: $file_ext
44     Object file: $object
45     Dependency result: $dep_object
46     All *linkable* object files: $link_objects
47     All *linkable* flat object files: $link_flat_objects
48     All *linkable* resource object files: $link_resobjects
49     Executable output file (full name): $exe_output
50     Executable dir (no name, no ext): $exe_dir
51     Executable name (no path, no ext): $exe_name
52     Executable extension: $exe_ext
53     Static library output file: $static_output
54     Dynamic library output file: $exe_output
55     Dynamic library DEF output file: $def_output
56     Resources output file: $resource_output
57     Objects output dir: $objects_output_dir
58 
59     Usual special chars apply: \t, \n, etc.
60     The command output should be ready for inclusion
61     in a Makefile (properly tab aligned but *no* tabs at the start of the string)
62     The macro substitution happens in compiler's MakefileGenerator.
63 */
64 
65 /// Enum categorizing compiler's output line as warning/error/info/normal
66 enum CompilerLineType
67 {
68     cltNormal = 0,
69     cltWarning,
70     cltError,
71     cltInfo
72 };
73 
74 // regexes array declaration
75 struct RegExStruct
76 {
RegExStructRegExStruct77     RegExStruct()
78         : desc(_("Unknown")), lt(cltError), filename(0), line(0), regex(_T("")), regexCompiled(false)
79     {
80         memset(msg, 0, sizeof(msg));
81     }
RegExStructRegExStruct82     RegExStruct(const RegExStruct& rhs)
83         : desc(rhs.desc), lt(rhs.lt), filename(rhs.filename), line(rhs.line), regex(rhs.regex), regexCompiled(false)
84     {
85         memcpy(msg, rhs.msg, sizeof(msg));
86     }
87     RegExStruct(const wxString&  _desc,
88                 CompilerLineType _lt,
89                 const wxString&  _regex,
90                 int              _msg,
91                 int              _filename = 0,
92                 int              _line     = 0,
93                 int              _msg2     = 0,
94                 int              _msg3     = 0)
descRegExStruct95         : desc(_desc), lt(_lt), filename(_filename), line(_line), regex(_regex), regexCompiled(false)
96     {
97         msg[0] = _msg;
98         msg[1] = _msg2;
99         msg[2] = _msg3;
100     }
101     RegExStruct& operator=(const RegExStruct &obj)
102     {
103         desc=obj.desc;
104         lt=obj.lt;
105         regex=obj.regex;
106         regexCompiled=false;
107         filename=obj.filename;
108         line=obj.line;
109         memcpy(msg, obj.msg, sizeof(msg));
110 
111         return *this;
112     }
113 
114     bool operator!=(const RegExStruct& other)
115     {
116         return !(*this == other);
117     }
118     bool operator==(const RegExStruct& other)
119     {
120         return (   desc     == other.desc
121                 && lt       == other.lt
122                 && regex    == other.regex
123                 && msg[0]   == other.msg[0]
124                 && msg[1]   == other.msg[1]
125                 && msg[2]   == other.msg[2]
126                 && filename == other.filename
127                 && line     == other.line );
128     }
129 
GetRegExStringRegExStruct130     wxString GetRegExString() const { return regex; }
SetRegExStringRegExStruct131     void SetRegExString(const wxString &str)
132     {
133         if (regex != str)
134         {
135             regex = str;
136             regexCompiled = false;
137         }
138     }
HasRegExRegExStruct139     bool HasRegEx() const { return !regex.empty(); }
GetRegExRegExStruct140     const wxRegEx& GetRegEx() const { CompileRegEx(); return regexObject; }
141 
142     wxString         desc;     // title of this regex
143     CompilerLineType lt;       // classify the line, if regex matches
144     int              msg[3];   // up-to 3 sub-expression nr for warning/error message
145     int              filename; // sub-expression nr for filename
146     int              line;     // sub-expression nr for line number
147     // if more than one sub-expressions are entered for msg,
148     // they are appended to each other, with one space in between.
149     // Appending takes place in the same order...
150 private:
CompileRegExRegExStruct151     void CompileRegEx() const
152     {
153         if (!regex.empty() && !regexCompiled)
154         {
155             regexObject.Compile(regex);
156             regexCompiled=true;
157         }
158     }
159     wxString        regex;    // the regex to match
160     mutable wxRegEx regexObject;
161     mutable bool    regexCompiled;
162 };
163 typedef std::vector<RegExStruct> RegExArray;
164 
165 /// Helper enum to retrieve compiler commands
166 enum CommandType
167 {
168     ctCompileObjectCmd = 0, ///< Compile object command, e.g. "$compiler $options $includes -c $file -o $object"
169     ctGenDependenciesCmd,   ///< Generate dependencies command
170     ctCompileResourceCmd,   ///< Compile Win32 resources command, e.g. "$rescomp -i $file -J rc -o $resource_output -O coff $includes"
171     ctLinkExeCmd,           ///< Link executable command, e.g. "$linker $libdirs -o $exe_output $link_objects $libs -mwindows"
172     ctLinkConsoleExeCmd,    ///< Link console executable command, e.g. "$linker $libdirs -o $exe_output $link_objects $libs"
173     ctLinkDynamicCmd,       ///< Link dynamic (dll) lib command, e.g. "$linker -shared -Wl,--output-def=$def_output -Wl,--out-implib=$static_output -Wl,--dll $libdirs $link_objects $libs -o $dynamic_output"
174     ctLinkStaticCmd,        ///< Link static lib command, e.g. "ar -r $output $link_objects\n\tranlib $static_output"
175     ctLinkNativeCmd,        ///< Link native binary command
176 
177     ctCount                 ///< Do NOT use
178 };
179 
180 
181 
182 /// Helper enum for type of compiler logging
183 enum CompilerLoggingType
184 {
185     clogFull,
186     clogSimple,
187     clogNone
188 };
189 
190 enum AutoDetectResult
191 {
192     adrDetected,
193     adrGuessed
194 };
195 
196 /// Struct to keep programs
197 struct CompilerPrograms
198 {
199     wxString C;         // C compiler
200     wxString CPP;       // C++ compiler
201     wxString LD;        // dynamic libs linker
202     wxString LIB;       // static libs linker
203     wxString WINDRES;   // resource compiler
204     wxString MAKE;      // make
205     wxString DBGconfig; // debugger config name = "debugger_settings_name:config_name"
206 };
207 
208 /// Struct to keep switches
209 struct DLLIMPORT CompilerSwitches
210 {
211     static const CompilerLoggingType defaultLogging = clogFull;
212     wxString includeDirs;         // -I
213     wxString libDirs;             // -L
214     wxString linkLibs;            // -l
215     wxString defines;             // -D
216     wxString genericSwitch;       // -
217     wxString objectExtension;     // o
218     bool forceFwdSlashes;         // force use forward slashes in file/path names (used by CompilerCommandGenerator)
219     bool forceLinkerUseQuotes;    // use quotes for filenames in linker command line (needed or not)?
220     bool forceCompilerUseQuotes;  // use quotes for filenames in compiler command line (needed or not)?
221     bool needDependencies;        // true
222     CompilerLoggingType logging;  // clogFull
223     wxString libPrefix;           // lib
224     wxString libExtension;        // a
225     bool linkerNeedsLibPrefix;    // when adding a link library, linker needs prefix?
226     bool linkerNeedsLibExtension; // when adding a link library, linker needs extension?
227     bool linkerNeedsPathResolved; // linker does not support libDirs; C::B must resolve file paths
228     bool supportsPCH;             // supports pre-compiled headers?
229     wxString PCHExtension;        // pre-compiled headers extension
230     bool UseFlatObjects;          // Use Flat object file names (no extra subdirs)?
231     bool UseFullSourcePaths;      // This is mainly a workaround for the GDB debugger, apparently I doesn't deal
232                                   // well with relative paths, therefore for GCC it is better to specify the source
233                                   // full to the compiler in a full path notation, for all other compilers it is
234                                   // suggested to keep this switch at false
235     bool Use83Paths;              // This is mainly a workaround for the resource compiler under Windows, apparently
236                                   // it doesn't deal well with spaces in the (include) path even if the path is quoted,
237                                   // therefore use 8.3 notation without spaces on Windows.
238                                   // However, this will apply to all include path's as other tools might have the
239                                   // same issue and it won't hurt to apply it to all include directories, if enabled.
240     wxChar includeDirSeparator;   // space
241     wxChar libDirSeparator;       // space
242     wxChar objectSeparator;       // space
243     int statusSuccess;            // 0    - treat exit-codes >= 0 and <= statusSuccess as success (do not set negative!)
244 
245     CompilerSwitches(); // constructor initializing the members, specific compilers should overrule if needed
246 };
247 
248 /// Struct for compiler/linker commands
249 struct CompilerTool
250 {
251     // extensions string will be converted to array by GetArrayFromString using DEFAULT_ARRAY_SEP (;)
252     // as separator
253     CompilerTool(const wxString& command_in = wxEmptyString, const wxString& extensions_in = wxEmptyString, const wxString& generatedFiles_in = wxEmptyString)
commandCompilerTool254         : command(command_in), extensions(GetArrayFromString(extensions_in)), generatedFiles(GetArrayFromString(generatedFiles_in))
255     {}
CompilerToolCompilerTool256     CompilerTool(const CompilerTool& rhs)
257         : command(rhs.command), extensions(rhs.extensions), generatedFiles(rhs.generatedFiles)
258     {}
259     bool operator==(const CompilerTool& rhs) const { return command == rhs.command && extensions == rhs.extensions && generatedFiles == rhs.generatedFiles; }
260     bool operator!=(const CompilerTool& rhs) const { return !(*this == rhs); }
261 
262     wxString      command;        ///< command to execute
263     wxArrayString extensions;     ///< file extensions for which the command will be invoked (no leading dot)
264     wxArrayString generatedFiles; ///< the native language files this command generates that should be further compiled
265 };
266 
267 typedef std::vector<CompilerTool> CompilerToolsVector;
268 
269 /**
270   * @brief Abstract base class for compilers.
271   *
272   * Create a derived class and add it in compilerfactory.cpp
273   */
274 class DLLIMPORT Compiler : public CompileOptionsBase
275 {
276     public:
277         static const wxString FilePathWithSpaces;
278         Compiler(const wxString& name, const wxString& ID, const wxString& parentID = wxEmptyString, int weight = 50);
279         ~Compiler() override;
280 
281         /** @brief Check if the compiler is actually valid (installed). */
282         virtual bool IsValid();
283 
284         /** @brief Check if the supplied string is a compiler warning/error */
285         virtual CompilerLineType CheckForWarningsAndErrors(const wxString& line);
286         /** @brief Returns warning/error filename. Use it after a call to CheckForWarningsAndErrors() */
GetLastErrorFilename()287         virtual wxString GetLastErrorFilename()             { return m_ErrorFilename; }
288         /** @brief Returns warning/error line number (as a string). Use it after a call to CheckForWarningsAndErrors() */
GetLastErrorLine()289         virtual wxString GetLastErrorLine()                 { return m_ErrorLine; }
290         /** @brief Returns warning/error actual string. Use it after a call to CheckForWarningsAndErrors() */
GetLastError()291         virtual wxString GetLastError()                     { return m_Error; }
292         /** @brief Get the compiler's name */
GetName()293         virtual const wxString& GetName() const             { return m_Name; }
294         /** @brief Get the compiler's master path (must contain "bin", "include" and "lib") */
GetMasterPath()295         virtual const wxString& GetMasterPath() const       { return m_MasterPath; }
296         /** @brief Get the compiler's extra paths */
GetExtraPaths()297         virtual const wxArrayString& GetExtraPaths() const  { return m_ExtraPaths; }
298         /** @brief Get the compiler's programs */
GetPrograms()299         virtual const CompilerPrograms& GetPrograms() const { return m_Programs; }
300         /** @brief Get the compiler's generic switches */
GetSwitches()301         virtual const CompilerSwitches& GetSwitches() const { return m_Switches; }
302         /** @brief Get the compiler's options */
GetOptions()303         virtual const CompilerOptions& GetOptions() const   { return m_Options; }
304         /** @brief Get a command based on CommandType
305           * @param ct The command type to process
306           * @param fileExtension the file's extension (no leading dot)
307           */
308         virtual const wxString& GetCommand(CommandType ct, const wxString& fileExtension = wxEmptyString) const;
309         /** @brief Get a compiler tool based on CommandType */
310         virtual const CompilerTool* GetCompilerTool(CommandType ct, const wxString& fileExtension = wxEmptyString) const;
311         /** @brief Get a command tool vector based on CommandType (used by advanced compiler dialog) */
GetCommandToolsVector(CommandType ct)312         virtual CompilerToolsVector& GetCommandToolsVector(CommandType ct) { return m_Commands[ct]; }
313         /** @brief Get the array of regexes used in errors/warnings recognition */
GetRegExArray()314         virtual const RegExArray& GetRegExArray(){ return m_RegExes; }
315         /** @brief Load the default (preset) array of regexes used in errors/warnings recognition */
316         virtual void LoadDefaultRegExArray(bool globalPrecedence = false);
317 
318         /** @brief Set the compiler's name */
SetName(const wxString & name)319         virtual void SetName(const wxString& name){ m_Name = name; }
320         /** @brief Set the compiler's master path (must contain "bin", "include" and "lib") */
SetMasterPath(const wxString & path)321         virtual void SetMasterPath(const wxString& path){ m_MasterPath = path; m_NeedValidityCheck = true; }
322         /** @brief Set the compiler's extra paths */
SetExtraPaths(const wxArrayString & paths)323         virtual void SetExtraPaths(const wxArrayString& paths){ m_ExtraPaths = paths; m_NeedValidityCheck = true; }
324         /** @brief Set the compiler's programs */
SetPrograms(const CompilerPrograms & programs)325         virtual void SetPrograms(const CompilerPrograms& programs){ m_Programs = programs; m_NeedValidityCheck = true; }
326         /** @brief Set the compiler's generic switches */
SetSwitches(const CompilerSwitches & switches)327         virtual void SetSwitches(const CompilerSwitches& switches){ m_Switches = switches; }
328         /** @brief Set the compiler's options */
SetOptions(const CompilerOptions & options)329         virtual void SetOptions(const CompilerOptions& options){ m_Options = options; }
330         /** @brief Set the array of regexes used in errors/warnings recognition */
SetRegExArray(const RegExArray & regexes)331         virtual void SetRegExArray(const RegExArray& regexes) { m_RegExes = regexes; }
332 
333 
334         /** @brief Save settings */
335         virtual void SaveSettings(const wxString& baseKey);
336         /** @brief Load settings */
337         virtual void LoadSettings(const wxString& baseKey);
338         /** @brief Reset settings to defaults.
339           * Put initialization code here or leave blank for standard XML loading.
340           * Call this from the default constructor.
341           */
342         virtual void Reset();
343         /** @brief Reload option flags (for copied compilers).
344           * Override if not using standard XML loading.
345           */
346         virtual void ReloadOptions();
347         /** @brief Try to auto-detect the compiler's installation directory */
348         virtual AutoDetectResult AutoDetectInstallationDir() = 0;
349 
350         /** @brief Get this compiler's unique ID */
GetID()351         const wxString& GetID() const { return m_ID; }
352         /** @brief Get this compiler's parent's unique ID */
GetParentID()353         const wxString& GetParentID() const { return m_ParentID; }
354 
355         /** @brief Get the command type descriptions (used in advanced compiler options) */
356         static wxString CommandTypeDescriptions[ctCount];
357 
358         /** @brief Set the compiler version string. Please override this virtual function
359           * with your own compiler-version detection code if you want to use this.
360           *
361           * By default this function does nothing. */
SetVersionString()362         virtual void SetVersionString() { return; };
363 
364         /** @brief Get the compiler version string */
GetVersionString()365         const wxString GetVersionString() const { return m_VersionString; };
366 
367         /** This is to be overridden, if compiler needs to alter the default
368           * command line generation.
369           */
370         virtual CompilerCommandGenerator* GetCommandGenerator(cbProject *project);
371 
SetCOnlyFlags(const wxString & flags)372         void SetCOnlyFlags(const wxString& flags)   { m_SortOptions[0] = flags; };
SetCPPOnlyFlags(const wxString & flags)373         void SetCPPOnlyFlags(const wxString& flags) { m_SortOptions[1] = flags; };
374 
GetCOnlyFlags()375         const wxString& GetCOnlyFlags()   { return m_SortOptions[0]; };
GetCPPOnlyFlags()376         const wxString& GetCPPOnlyFlags() { return m_SortOptions[1]; };
377 
378         /** @brief Do compiler writes multi-line messages? */
WithMultiLineMsg()379         bool WithMultiLineMsg() { return m_MultiLineMessages; };
380 
381         /// @brief Returns messages which might be useful to the use for debugging why the
382         /// compiler is invalid. Call only after IsValid returns false.
383         wxString MakeInvalidCompilerMessages() const;
384     protected:
385         friend class CompilerFactory;
386         Compiler(const Compiler& other); // copy ctor to copy everything but update m_ID
387 
388         /** @brief Implement this in new compilers, to return a new copy */
389         virtual Compiler* CreateCopy() = 0;
390 
391         // purposely non-virtual
IsUniqueID(const wxString & ID)392         bool IsUniqueID(const wxString& ID){ return m_CompilerIDs.Index(ID) == wxNOT_FOUND; }
393         // converts, if needed, m_ID to something that is valid
394         void MakeValidID();
395 
396         // load options from the corresponding options_<name>.xml
397         void LoadDefaultOptions(const wxString& name, int recursion = 0);
398         // load array of regexes from the corresponding options_<name>.xml
399         void LoadRegExArray(const wxString& name, bool globalPrecedence = false, int recursion = 0);
400 
401         bool EvalXMLCondition(const wxXmlNode* node);
402         wxString GetExecName(const wxString& name);
403 
404         // keeps a copy of current settings (works only the first time it's called)
405         void MirrorCurrentSettings();
406 
407         // set the following members in your class
408         wxString            m_Name;
409         wxString            m_MasterPath;
410         wxArrayString       m_ExtraPaths;
411         CompilerToolsVector m_Commands[ctCount];
412         CompilerPrograms    m_Programs;
413         CompilerSwitches    m_Switches;
414         CompilerOptions     m_Options;
415         RegExArray          m_RegExes;
416         wxString            m_ErrorFilename;
417         wxString            m_ErrorLine;
418         wxString            m_Error;
419         wxString            m_VersionString;
420         wxString            m_SortOptions[2]; // m_SortOptions[0] == C-only flags; m_SortOptions[1] == C++-only flags
421 
422         int m_Weight; // lower means listed sooner (try to keep between 0 and 100)
423         bool m_MultiLineMessages; // true if the compiler writes multi-line error/warning messages
424     private:
425         wxString m_ID;
426         wxString m_ParentID; // -1 for builtin compilers, the builtin compiler's ID to derive from for user compilers...
427         static wxArrayString m_CompilerIDs; // map to guarantee unique IDs
428         bool m_Valid; // 'valid' flag
429         bool m_NeedValidityCheck; // flag to re-check validity (raised when changing compiler paths)
430 
431         // "mirror" default settings for comparing when saving (to save only those that differ from defaults)
432         struct MirrorSettings
433         {
434             wxString         Name;
435             wxString         MasterPath;
436             wxArrayString    ExtraPaths;
437             CompilerPrograms Programs;
438 
439             // these are the CompileOptionsBase settings that each compiler keeps on a global level
440             wxArrayString CompilerOptions_;
441             wxArrayString ResourceCompilerOptions;
442             wxArrayString LinkerOptions;
443             wxArrayString IncludeDirs;
444             wxArrayString ResIncludeDirs;
445             wxArrayString LibDirs;
446             wxArrayString LinkLibs;
447             wxArrayString CmdsBefore;
448             wxArrayString CmdsAfter;
449 
450             // below are the settings that the user is asked to revert to defaults (if defaults have changed)
451             CompilerToolsVector Commands[ctCount];
452             CompilerSwitches    Switches;
453             CompilerOptions     Options;
454             RegExArray          RegExes;
455 
456             wxString SortOptions[2];
457         };
458         MirrorSettings m_Mirror;
459         bool           m_Mirrored; // flag to only mirror the settings once
460 };
461 
462 #endif // COMPILER_H
463