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