ide; documentor; epj2make; installer: Moved IDE dependency out of IDESettings
[sdk] / ide / src / project / ProjectConfig.ec
1 import "Project"
2
3 enum DirExpressionType { unknown, targetDir, intermediateObjectsDir };  // "type" is not right
4
5 class DirExpression : struct
6 {
7    char * dir;
8    DirExpressionType type;
9
10    ~DirExpression()
11    {
12       delete dir;
13    }
14
15    property const char * dir
16    {
17       get
18       {
19          return dir ? dir : "";
20       }
21       set
22       {
23          delete dir;
24          if(value && value[0])
25             dir = CopyString(value);
26          else
27             dir = CopyString("");
28       }
29    }
30
31    void Evaluate(const char * expression, Project project, CompilerConfig compiler, ProjectConfig config, int bitDepth)
32    {
33       int len;
34       const char * expr = expression;
35       if(!expr || !expr[0])
36       {
37          if(ideSettings)
38          {
39             if(type == targetDir)
40                expr = ideSettings.projectDefaultTargetDir;
41             else if(type == intermediateObjectsDir)
42                expr = ideSettings.projectDefaultIntermediateObjDir;
43          }
44          if(!expr || !expr[0])
45             expr = defaultObjDirExpression;
46       }
47       if((len = strlen(expr)))
48       {
49          int c, d;
50          const char * configName = config && config.name && config.name[0] ? config.name : "Common";
51          const char * moduleName = project && project.moduleName ? project.moduleName : "";
52          const char * compilerName = (compiler && compiler.name) ? compiler.name : defaultCompilerName;
53          const char * targetPlatformName = compiler && compiler.targetPlatform ? compiler.targetPlatform : "";
54          char buffer[MAX_LOCATION];
55          for(c = 0, d = 0; c < len; c++)
56          {
57             if(expr[c] == '$' && c < len - 1 && expr[c + 1] == '(')
58             {
59                int i;
60                bool matched = false;
61                for(i = c + 2; i < len; i++)
62                {
63                   if(expr[i] == ')')
64                   {
65                      int n = i - c - 2;
66                      if(n > 0)
67                      {
68                         if(!strnicmp(&expr[c + 2], "Config", n) || !strnicmp(&expr[c + 2], "Config", n))
69                         {
70                            buffer[d] = '\0';
71                            strcat(buffer, configName);
72                            CamelCase(&buffer[d]);
73                            d += strlen(configName);
74                            c = i;
75                            matched = true;
76                         }
77                         else if(!strnicmp(&expr[c + 2], "Module", n) || !strnicmp(&expr[c + 2], "Project", n))
78                         {
79                            buffer[d] = '\0';
80                            strcat(buffer, moduleName);
81                            //CamelCase(&buffer[d]);
82                            d += strlen(moduleName);
83                            c = i;
84                            matched = true;
85                         }
86                         else if(!strnicmp(&expr[c + 2], "Platform", n))
87                         {
88                            buffer[d] = '\0';
89                            strcat(buffer, targetPlatformName);
90                            CamelCase(&buffer[d]);
91                            d += strlen(targetPlatformName);
92                            c = i;
93                            matched = true;
94                         }
95                         else if(!strnicmp(&expr[c + 2], "Compiler", n))
96                         {
97                            buffer[d] = '\0';
98                            strcat(buffer, compilerName);
99                            CamelCase(&buffer[d]);
100                            d += strlen(compilerName);
101                            c = i;
102                            matched = true;
103                         }
104                         else if(!strnicmp(&expr[c + 2], "Debug_Suffix", n))
105                         {
106                            // We don't support .debug from the IDE yet...
107                            c = i;
108                            matched = true;
109                         }
110                         else if(!strnicmp(&expr[c + 2], "Compiler_Suffix", n))
111                         {
112                            if(bitDepth || (compilerName[0] && strcmpi(compilerName, "default")))
113                            {
114                               if(compilerName[0] && strcmpi(compilerName, "default"))
115                               {
116                                  buffer[d++] = '.';
117                                  buffer[d] = '\0';
118                                  strcat(buffer, compilerName);
119                                  CamelCase(&buffer[d]);
120                                  d += strlen(compilerName);
121                               }
122                               if(bitDepth == 32)
123                               {
124                                  strcat(buffer, ".x32");
125                                  d += 4;
126                               }
127                               else if(bitDepth == 64)
128                               {
129                                  strcat(buffer, ".x64");
130                                  d += 4;
131                               }
132                            }
133                            c = i;
134                            matched = true;
135                         }
136                         else if(compiler && compiler.environmentVars && compiler.environmentVars.count)
137                         {
138                            for(ev : compiler.environmentVars;
139                                  ev.name && ev.string && ev.name[0] && ev.string[0] && !strnicmp(&expr[c + 2], ev.name, n) && strlen(ev.name) == n)
140                            {
141                               buffer[d] = '\0';
142 #if defined(__WIN32__)
143                               ChangeCh(ev.string, '\\', '/');
144 #endif
145                               strcat(buffer, ev.string);
146 #if defined(__WIN32__)
147                               ChangeCh(ev.string, '/', '\\');
148 #endif
149                               d += strlen(ev.string);
150                               c = i;
151                               matched = true;
152                               break;
153                            }
154                         }
155                         if(!matched)
156                            buffer[d++] = expr[c];
157                      }
158                      else
159                      {
160                         buffer[d++] = expr[c];
161                      }
162                      i = len - 1;
163                      break;
164                   }
165                   else if(expr[i] == '\\' || expr[i] == '/')
166                   {
167                      buffer[d++] = '\0';
168                      strncat(buffer, &expr[i], i - c);
169                      d += i - c;
170                      c = i;
171                      i = len - 1;
172                      break;
173                   }
174                }
175                if(i == len)
176                   buffer[d++] = expr[c];
177             }
178             else
179             {
180                buffer[d++] = expr[c];
181             }
182          }
183          buffer[d] = '\0';
184          if(dir && strcmp(buffer, dir))
185             delete dir;
186          if(!dir)
187             dir = CopyString(buffer);
188       }
189       else
190       {
191          delete dir;
192          dir = CopyString("");
193       }
194    }
195 }
196
197 public enum TargetTypes { unset, executable, sharedLibrary, staticLibrary };
198 public enum OptimizationStrategy { unset, none, speed, size };
199 public enum WarningsOption { unset, normal, none, all }; // TOCHECK: More options?
200 public enum BuildBitDepth { all, bits32, bits64 };
201
202 Array<String> CopyArrayString(Array<String> array)
203 {
204    Array<String> copy = null;
205    if(array)
206    {
207       copy = { };
208       for(s : array) copy.Add(CopyString(s));
209    }
210    return copy;
211 }
212
213 public class ProjectOptions
214 {
215 public:
216    // Compiler Options
217    property SetBool allWarnings
218    {
219       set
220       {
221          if(value == true)
222             warnings = all;
223       }
224    }
225    WarningsOption warnings;
226    SetBool debug;
227    SetBool memoryGuard;
228    SetBool profile;
229    SetBool noLineNumbers;
230    OptimizationStrategy optimization;
231    Array<String> preprocessorDefinitions;
232    property Array<String> includeDirs
233    {
234       set
235       {
236          if(includeDirs)
237             includeDirs.Free();
238          if(value && value.count)
239          {
240             if(!includeDirs)
241                includeDirs = { };
242             for(s : value)
243                includeDirs.Add(CopyValidateMakefilePath(s));
244             value.Free();
245             delete value;
246          }
247          else
248             delete includeDirs;
249       }
250       get { return includeDirs; }
251       isset { return  includeDirs && includeDirs.count; }
252    }
253    String defaultNameSpace;
254    SetBool strictNameSpaces;
255
256    // Linker Options
257    TargetTypes targetType;
258    // NOTE: The JSON Parser deletes strings after setting a String property, so we do a copy here.
259    //       (This behavior is different from Objects (class instances) values which are not deleted)
260    //       Code calling these properties should *NOT* use CopyString().
261    property char * targetFileName
262    {
263       set { delete targetFileName; if(value && value[0]) targetFileName = CopyValidateMakefilePath(value); }
264       get { return targetFileName; }
265       isset { return targetFileName && targetFileName[0]; }
266    }
267    property char * targetDirectory
268    {
269       set { delete targetDirectory; if(value /*&& value[0]*/) targetDirectory = CopyValidateMakefilePath(value); }
270       get { return targetDirectory; }
271       isset { return targetDirectory != null/*&& targetDirectory[0]*/; }
272    }
273    property char * objectsDirectory
274    {
275       set { delete objectsDirectory; if(value /*&& value[0]*/) objectsDirectory = CopyValidateMakefilePath(value); }
276       get { return objectsDirectory; }
277       isset { return objectsDirectory != null/*&& objectsDirectory[0]*/; }
278    }
279    Array<String> libraries;
280    Array<String> compilerOptions;
281    Array<String> linkerOptions;
282    property Array<String> libraryDirs
283    {
284       set
285       {
286          if(libraryDirs)
287             libraryDirs.Free();
288          if(value && value.count)
289          {
290             if(!libraryDirs)
291                libraryDirs = { };
292             for(s : value)
293                libraryDirs.Add(CopyValidateMakefilePath(s));
294             value.Free(); // why do I have to do this here? it's a property, shouldn't json deal with this?
295             delete value;
296          }
297          else
298             delete libraryDirs;
299       }
300       get { return libraryDirs; }
301       isset { return  libraryDirs && libraryDirs.count; }
302    }
303    SetBool console;
304    SetBool compress;
305
306    // todo; move those to compiler/linker sections
307    SetBool excludeFromBuild;
308    BuildBitDepth buildBitDepth;
309    SetBool fastMath;
310
311    property Array<String> prebuildCommands
312    {
313       set
314       {
315          if(prebuildCommands)
316             prebuildCommands.Free();
317          if(value && value.count)
318          {
319             if(!prebuildCommands)
320                prebuildCommands = { };
321             for(s : value)
322                prebuildCommands.Add(CopyValidateMakefilePath(s));
323             value.Free();
324             delete value;
325          }
326          else
327             delete prebuildCommands;
328       }
329       get { return prebuildCommands; }
330       isset { return  prebuildCommands && prebuildCommands.count; }
331    }
332    property Array<String> postbuildCommands
333    {
334       set
335       {
336          if(postbuildCommands)
337             postbuildCommands.Free();
338          if(value && value.count)
339          {
340             if(!postbuildCommands)
341                postbuildCommands = { };
342             for(s : value)
343                postbuildCommands.Add(CopyValidateMakefilePath(s));
344             value.Free();
345             delete value;
346          }
347          else
348             delete postbuildCommands;
349       }
350       get { return postbuildCommands; }
351       isset { return  postbuildCommands && postbuildCommands.count; }
352    }
353    property Array<String> installCommands
354    {
355       set
356       {
357          if(installCommands)
358             installCommands.Free();
359          if(value && value.count)
360          {
361             if(!installCommands)
362                installCommands = { };
363             for(s : value)
364                installCommands.Add(CopyValidateMakefilePath(s));
365             value.Free();
366             delete value;
367          }
368          else
369             delete installCommands;
370       }
371       get { return installCommands; }
372       isset { return  installCommands && installCommands.count; }
373    }
374
375    ProjectOptions Copy()
376    {
377       // TODO: We'll want some solution so that we can use OnCopy for copying containers (Array<String>)
378       return
379       {
380          warnings = warnings,
381          debug = debug,
382          memoryGuard = memoryGuard,
383          profile = profile,
384          noLineNumbers = noLineNumbers;
385          optimization = optimization,
386          defaultNameSpace = CopyString(defaultNameSpace),
387          strictNameSpaces = strictNameSpaces,
388          targetType = targetType,
389          targetFileName = /*CopyString(*/targetFileName/*)*/,
390          targetDirectory = /*CopyString(*/targetDirectory/*)*/,
391          objectsDirectory = /*CopyString(*/objectsDirectory/*)*/,
392          console = console,
393          compress = compress,
394          excludeFromBuild = excludeFromBuild,
395          fastMath = fastMath,
396          preprocessorDefinitions = CopyArrayString(preprocessorDefinitions),
397          includeDirs = CopyArrayString(includeDirs),
398          libraries = CopyArrayString(libraries),
399          compilerOptions = CopyArrayString(compilerOptions),
400          linkerOptions = CopyArrayString(linkerOptions),
401          libraryDirs = CopyArrayString(libraryDirs),
402          prebuildCommands = CopyArrayString(prebuildCommands),
403          postbuildCommands = CopyArrayString(postbuildCommands),
404          installCommands = CopyArrayString(installCommands)
405       };
406    }
407
408 #ifdef _DEBUG
409    void print()
410    {
411       PrintLn("warnings:", warnings);
412       PrintLn("debug:", debug);
413       PrintLn("memoryGuard:", memoryGuard);
414       PrintLn("profile:", profile);
415       //PrintLn("noLineNumbers:", noLineNumbers);
416       PrintLn("optimization:", optimization);
417
418       PrintLn("fastMath:", fastMath);
419
420       PrintLn("preprocessorDefinitions:", preprocessorDefinitions);
421       PrintLn("compilerOptions:", compilerOptions);
422       PrintLn("linkerOptions:", linkerOptions);
423       PrintLn("includeDirs:", includeDirs);
424
425       PrintLn("");
426    }
427 #endif
428
429    ~ProjectOptions()
430    {
431       if(preprocessorDefinitions) { preprocessorDefinitions.Free(); delete preprocessorDefinitions; }
432       if(includeDirs) { includeDirs.Free(); delete includeDirs; }
433       delete defaultNameSpace;
434       delete targetFileName;
435       delete targetDirectory;
436       delete objectsDirectory;
437       if(libraries) { libraries.Free(); delete libraries; }
438       if(compilerOptions) { compilerOptions.Free(); delete compilerOptions; }
439       if(linkerOptions) { linkerOptions.Free(); delete linkerOptions; }
440       if(libraryDirs) { libraryDirs.Free(); delete libraryDirs; }
441       if(prebuildCommands) { prebuildCommands.Free(); delete prebuildCommands; }
442       if(postbuildCommands) { postbuildCommands.Free(); delete postbuildCommands; }
443       if(installCommands) { installCommands.Free(); delete installCommands; }
444    }
445 private:
446    Array<String> includeDirs;
447    String targetFileName;
448    String targetDirectory;
449    String objectsDirectory;
450    Array<String> libraryDirs;
451    Array<String> prebuildCommands;
452    Array<String> postbuildCommands;
453    Array<String> installCommands;
454
455    property bool isEmpty
456    {
457       get
458       {
459          if(warnings == unset &&
460             debug == unset &&
461             memoryGuard == unset &&
462             profile == unset &&
463             noLineNumbers == unset &&
464             optimization == unset &&
465             !preprocessorDefinitions &&
466             (!includeDirs || !includeDirs.count) &&
467             !defaultNameSpace &&
468             strictNameSpaces == unset &&
469             targetType == unset &&
470             !targetFileName &&
471             !targetDirectory &&
472             !objectsDirectory &&
473             !libraries &&
474             !compilerOptions &&
475             !linkerOptions &&
476             (!libraryDirs || !libraryDirs.count) &&
477             console == unset &&
478             compress == unset &&
479             excludeFromBuild == unset &&
480             fastMath == unset &&
481             (!prebuildCommands || !prebuildCommands.count) &&
482             (!postbuildCommands || !postbuildCommands.count) &&
483             (!installCommands || !installCommands.count))
484             return true;
485          return false;
486       }
487    }
488 }
489
490 public class PlatformOptions
491 {
492 public:
493    String name;
494    property ProjectOptions options { get { return options; } set { options = value; } isset { return options && !options.isEmpty; } }
495
496    ~PlatformOptions()
497    {
498       delete name;
499       delete options;
500    }
501
502    PlatformOptions Copy()
503    {
504       return
505       {
506          CopyString(name),
507          options ? options.Copy() : null
508       };
509    }
510 private:
511    ProjectOptions options;
512 }
513
514 class ProjectConfig : struct
515 {
516 public:
517    String name;
518    property ProjectOptions options { get { return options; } set { options = value; } isset { return options && !options.isEmpty; } }
519    property Array<PlatformOptions> platforms
520    {
521       get { return platforms; }
522       set
523       {
524          if(platforms) { platforms.Free(); delete platforms; }
525          if(value)
526          {
527             List<PlatformOptions> empty { };
528             Iterator<PlatformOptions> it { value };
529             platforms = value;
530             for(p : platforms; !p.options || p.options.isEmpty) empty.Add(p);
531             for(p : empty; it.Find(p)) platforms.Delete(it.pointer);
532             delete empty;
533          }
534       }
535       isset
536       {
537          if(platforms)
538          {
539             for(p : platforms)
540             {
541                if(p.options && !p.options.isEmpty)
542                   return true;
543             }
544          }
545          return false;
546       }
547    }
548
549 private:
550    ProjectOptions options;
551    bool makingModified;
552    bool compilingModified, linkingModified, symbolGenModified;
553    Array<PlatformOptions> platforms;
554
555    ~ProjectConfig()
556    {
557       // Configuration
558       delete name;
559       delete options;
560       if(platforms) { platforms.Free(); delete platforms; }
561    }
562
563    ProjectConfig Copy()
564    {
565       Array<PlatformOptions> platforms = null;
566       if(this.platforms)
567       {
568          platforms = { };
569          for(p : this.platforms)
570          {
571             platforms.Add(p.Copy());
572          }
573       }
574       return
575       {
576          CopyString(name),
577          options ? options.Copy() : null,
578          platforms
579       };
580    }
581 }