buildsystem, epj2make, ide: support Emscripten compiler.
[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 && 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                bool matched = false;
65                for(i = c + 2; i < len; i++)
66                {
67                   if(expr[i] == ')')
68                   {
69                      int n = i - c - 2;
70                      if(n > 0)
71                      {
72                         if(!strnicmp(&expr[c + 2], "Config", n) || !strnicmp(&expr[c + 2], "Config", n))
73                         {
74                            buffer[d] = '\0';
75                            strcat(buffer, configName);
76                            CamelCase(&buffer[d]);
77                            d += strlen(configName);
78                            c = i;
79                            matched = true;
80                         }
81                         else if(!strnicmp(&expr[c + 2], "Module", n) || !strnicmp(&expr[c + 2], "Project", n))
82                         {
83                            buffer[d] = '\0';
84                            strcat(buffer, moduleName);
85                            //CamelCase(&buffer[d]);
86                            d += strlen(moduleName);
87                            c = i;
88                            matched = true;
89                         }
90                         else if(!strnicmp(&expr[c + 2], "Platform", n))
91                         {
92                            buffer[d] = '\0';
93                            strcat(buffer, targetPlatformName);
94                            CamelCase(&buffer[d]);
95                            d += strlen(targetPlatformName);
96                            c = i;
97                            matched = true;
98                         }
99                         else if(!strnicmp(&expr[c + 2], "Compiler", n))
100                         {
101                            buffer[d] = '\0';
102                            strcat(buffer, compilerName);
103                            CamelCase(&buffer[d]);
104                            d += strlen(compilerName);
105                            c = i;
106                            matched = true;
107                         }
108                         else if(!strnicmp(&expr[c + 2], "Debug_Suffix", n))
109                         {
110                            // We don't support .debug from the IDE yet...
111                            c = i;
112                            matched = true;
113                         }
114                         else if(!strnicmp(&expr[c + 2], "Compiler_Suffix", n))
115                         {
116                            if(bitDepth || (compilerName[0] && strcmpi(compilerName, "default")))
117                            {
118                               if(compilerName[0] && strcmpi(compilerName, "default"))
119                               {
120                                  buffer[d++] = '.';
121                                  buffer[d] = '\0';
122                                  strcat(buffer, compilerName);
123                                  CamelCase(&buffer[d]);
124                                  d += strlen(compilerName);
125                               }
126                               if(bitDepth == 32)
127                               {
128                                  strcat(buffer, ".x32");
129                                  d += 4;
130                               }
131                               else if(bitDepth == 64)
132                               {
133                                  strcat(buffer, ".x64");
134                                  d += 4;
135                               }
136                            }
137                            c = i;
138                            matched = true;
139                         }
140                         else if(compiler && compiler.environmentVars && compiler.environmentVars.count)
141                         {
142                            for(ev : compiler.environmentVars;
143                                  ev.name && ev.string && ev.name[0] && ev.string[0] && !strnicmp(&expr[c + 2], ev.name, n) && strlen(ev.name) == n)
144                            {
145                               buffer[d] = '\0';
146                               ChangeCh(ev.string, '\\', '/');
147                               strcat(buffer, ev.string);
148                               ChangeCh(ev.string, '/', '\\');
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       //...
419       //PrintLn("dddddddd:", dddddddd);
420
421       PrintLn("fastMath:", fastMath);
422
423       PrintLn("preprocessorDefinitions:", preprocessorDefinitions);
424       PrintLn("compilerOptions:", compilerOptions);
425       PrintLn("linkerOptions:", linkerOptions);
426       PrintLn("includeDirs:", includeDirs);
427
428       //...
429       //PrintLn("dddddddd:", dddddddd);
430
431       PrintLn("");
432    }
433 #endif
434
435    ~ProjectOptions()
436    {
437       if(preprocessorDefinitions) { preprocessorDefinitions.Free(); delete preprocessorDefinitions; }
438       if(includeDirs) { includeDirs.Free(); delete includeDirs; }
439       delete defaultNameSpace;
440       delete targetFileName;
441       delete targetDirectory;
442       delete objectsDirectory;
443       if(libraries) { libraries.Free(); delete libraries; }
444       if(compilerOptions) { compilerOptions.Free(); delete compilerOptions; }
445       if(linkerOptions) { linkerOptions.Free(); delete linkerOptions; }
446       if(libraryDirs) { libraryDirs.Free(); delete libraryDirs; }
447       if(prebuildCommands) { prebuildCommands.Free(); delete prebuildCommands; }
448       if(postbuildCommands) { postbuildCommands.Free(); delete postbuildCommands; }
449       if(installCommands) { installCommands.Free(); delete installCommands; }
450    }
451 private:
452    Array<String> includeDirs;
453    String targetFileName;
454    String targetDirectory;
455    String objectsDirectory;
456    Array<String> libraryDirs;
457    Array<String> prebuildCommands;
458    Array<String> postbuildCommands;
459    Array<String> installCommands;
460
461    property bool isEmpty
462    {
463       get
464       {
465          if(warnings == unset &&
466             debug == unset &&
467             memoryGuard == unset &&
468             profile == unset &&
469             noLineNumbers == unset &&
470             optimization == unset &&
471             !preprocessorDefinitions &&
472             (!includeDirs || !includeDirs.count) &&
473             !defaultNameSpace &&
474             strictNameSpaces == unset &&
475             targetType == unset &&
476             !targetFileName &&
477             !targetDirectory &&
478             !objectsDirectory &&
479             !libraries &&
480             !compilerOptions &&
481             !linkerOptions &&
482             (!libraryDirs || !libraryDirs.count) &&
483             console == unset &&
484             compress == unset &&
485             excludeFromBuild == unset &&
486             fastMath == unset &&
487             (!prebuildCommands || !prebuildCommands.count) &&
488             (!postbuildCommands || !postbuildCommands.count) &&
489             (!installCommands || !installCommands.count))
490             return true;
491          return false;
492       }
493    }
494 }
495
496 public class PlatformOptions
497 {
498 public:
499    String name;
500    property ProjectOptions options { get { return options; } set { options = value; } isset { return options && !options.isEmpty; } }
501
502    ~PlatformOptions()
503    {
504       delete name;
505       delete options;
506    }
507
508    PlatformOptions Copy()
509    {
510       return
511       {
512          CopyString(name),
513          options ? options.Copy() : null
514       };
515    }
516 private:
517    ProjectOptions options;
518 }
519
520 class ProjectConfig : struct
521 {
522 public:
523    String name;
524    property ProjectOptions options { get { return options; } set { options = value; } isset { return options && !options.isEmpty; } }
525    property Array<PlatformOptions> platforms
526    {
527       get { return platforms; }
528       set
529       {
530          if(platforms) { platforms.Free(); delete platforms; }
531          if(value)
532          {
533             List<PlatformOptions> empty { };
534             Iterator<PlatformOptions> it { value };
535             platforms = value;
536             for(p : platforms; !p.options || p.options.isEmpty) empty.Add(p);
537             for(p : empty; it.Find(p)) platforms.Delete(it.pointer);
538             delete empty;
539          }
540       }
541       isset
542       {
543          if(platforms)
544          {
545             for(p : platforms)
546             {
547                if(p.options && !p.options.isEmpty)
548                   return true;
549             }
550          }
551          return false;
552       }
553    }
554
555 private:
556    ProjectOptions options;
557    bool makingModified;
558    bool compilingModified, linkingModified, symbolGenModified;
559    Array<PlatformOptions> platforms;
560
561    ~ProjectConfig()
562    {
563       // Configuration
564       delete name;
565       delete options;
566       if(platforms) { platforms.Free(); delete platforms; }
567    }
568
569    ProjectConfig Copy()
570    {
571       Array<PlatformOptions> platforms = null;
572       if(this.platforms)
573       {
574          platforms = { };
575          for(p : this.platforms)
576          {
577             platforms.Add(p.Copy());
578          }
579       }
580       return
581       {
582          CopyString(name),
583          options ? options.Copy() : null,
584          platforms
585       };
586    }
587 }