source: branches/dev-jw-2590/Compiler/ModelicaCompiler/src/jastadd/ModelicaCompiler.jrag @ 13967

Last change on this file since 13967 was 13967, checked in by jwedin, 5 weeks ago

Moved buildNodeCountMap from ASTNode to UtilInterface. #5865

File size: 104.6 KB
Line 
1/*
2    Copyright (C) 2009-2017 Modelon AB
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, version 3 of the License.
7
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12
13    You should have received a copy of the GNU General Public License
14    along with this program.  If not, see <http://www.gnu.org/licenses/>.
15*/
16
17
18import java.io.BufferedReader;
19import java.io.BufferedWriter;
20import java.io.ByteArrayOutputStream;
21import java.io.File;
22import java.io.FileInputStream;
23import java.io.FileNotFoundException;
24import java.io.FileReader;
25import java.io.FileWriter;
26import java.io.IOException;
27import java.io.OutputStream;
28import java.io.PrintStream;
29import java.io.PrintWriter;
30import java.io.Reader;
31import java.io.StringWriter;
32import java.lang.InterruptedException;
33import java.lang.StringBuilder;
34import java.nio.channels.FileChannel;
35import java.nio.file.Path;
36import java.nio.file.Paths;
37import java.util.Arrays;
38import java.util.ArrayList;
39import java.util.Collection;
40import java.util.HashMap;
41import java.util.HashSet;
42import java.util.LinkedHashSet;
43import java.util.LinkedList;
44import java.util.Map;
45import java.util.Stack;
46import java.util.regex.Pattern;
47import java.util.zip.ZipOutputStream;
48import java.util.zip.ZipEntry;
49import java.util.Set;
50import java.util.Iterator;
51
52import javax.xml.parsers.ParserConfigurationException;
53import javax.xml.xpath.XPathExpressionException;
54
55import org.jmodelica.util.logging.ModelicaLogger;
56import org.jmodelica.util.logging.MemoryLogger;
57import org.jmodelica.util.logging.Level;
58import org.jmodelica.common.options.AbstractOptionRegistry;
59import org.jmodelica.common.options.AbstractOptionRegistry.UnknownOptionException;
60import org.jmodelica.util.Arguments;
61import org.jmodelica.util.SymbolValueFixer;
62import org.jmodelica.util.EnvironmentUtils;
63import org.jmodelica.util.exceptions.ModelicaException;
64import org.jmodelica.util.exceptions.InternalCompilerError;
65import org.jmodelica.util.MemorySpider;
66import org.jmodelica.util.exceptions.CompilerException;
67import org.jmodelica.util.exceptions.IllegalCompilerArgumentException;
68import org.jmodelica.util.exceptions.ModelicaClassNotFoundException;
69import org.jmodelica.util.exceptions.JModelicaHomeNotFoundException;
70import org.jmodelica.util.exceptions.PackingFailedException;
71import org.jmodelica.util.exceptions.CcodeCompilationException;
72import org.jmodelica.util.problemHandling.ProblemProducer;
73import org.jmodelica.util.PassAndForget;
74import org.jmodelica.util.logging.IllegalLogStringException;
75import org.jmodelica.util.ErrorCheckType;
76import org.jmodelica.util.streams.*;
77import org.jmodelica.util.files.*;
78import org.jmodelica.util.ccompiler.CCompilerArguments;
79import org.jmodelica.util.ccompiler.CCompilerDelegator;
80import org.jmodelica.util.ccompiler.CCompilerDelegator.Creator;
81import org.jmodelica.util.ccompiler.CCompilerTarget;
82import org.jmodelica.util.ccompiler.GccCompilerDelegator;
83import org.jmodelica.common.LogContainer;
84import org.jmodelica.modelica.compiler.generated.OptionRegistry;
85
86import org.xml.sax.SAXException;
87
88aspect ModelicaCompilerMain {
89 
90/**
91 *
92 * Main compiler class which bundles the tasks needed to compile a Modelica
93 * model.
94 * <p>
95 * There are two usages with this class:
96 * -# Compile in one step either from the command line or by calling the static
97 * method <compileModel> in your own class.
98 * -# Split compilation into several steps by calling the static methods
99 * in your own class.
100 * <p>
101 * Use (1) for a simple and compact way of compiling a Modelica model. As a
102 * minimum, provide the modelfile name and class name as command line arguments.
103 * Optional arguments are XML template and c template files which are needed for
104 * code generation. If any of these are ommitted no code generation will be
105 * performed.
106 * <p>
107 * Command line example without code generation:<br>
108 * <code>org.jmodelica.applications.ModelicaCompiler myModels/models.mo models.model1</code>
109 * <p>
110 * Command line example with code generation: <br>
111 * <code>org.jmodelica.applications.ModelicaCompiler myModels/models.mo models.model1
112 * XMLtemplate1.xml XMLtemplate2.xml cppTemplate.cpp</code>
113 * <p>
114 * Logging can be set with the optional argument -log=d, v, i, w or e where:
115 * <p>
116 *  - d : log debug, verbose, info, warning and error messages
117 *  - v : log verbose, info, warning and error messages
118 *  - i : log info, warning and error messages
119 *  - w : log warning and error messages
120 *  - e : log error messages only (default if the log option is not used)
121 * <p>
122 * Example with log level set to INFO: <br>
123 * <code>org.jmodelica.applications.ModelicaCompiler -log=i myModels/models.mo
124 * models.model1</code>
125 * <p>
126 * The logs will be printed to standard out.
127 * <p>
128 *
129 * For method (2), the compilation steps are divided into 4 tasks which can be
130 * used via the methods:
131 * -# parseModel (source code -> attributed source representation)
132 * -# instantiateModel (source representation -> instance model)
133 * -# flattenModel (instance model -> flattened model)
134 * -# generateCode (flattened model -> c code and XML code)
135 * <p>
136 * They must be called in this order. Use provided methods to get/set logging
137 * level.
138 *
139 */
140public class ModelicaCompiler implements LogContainer {
141   
142    public static final Level DEFAULT_LEVEL = Level.ERROR;
143    protected static ModelicaLogger log = new StreamingLogger(ModelicaCompiler.DEFAULT_LEVEL, System.out);
144   
145    private CCompilerDelegator delegator = null;
146    private String delegator_name = null;
147    private OptionRegistry options = null;
148    private DiagnosticsGenerator diagGenerator = null;
149   
150    protected boolean dumpMemoryUse = false;
151    protected int dumpMemoryUseMinSize = 2 * 1024;
152    protected boolean findFlatToInstanceLinks = false;
153   
154    // If true, assume that JMODELICA_HOME points to the source folder - for easier debugging while developing
155    protected boolean debugSrcIsHome = false;
156    public void setDebugSrcIsHome(boolean b) {
157        debugSrcIsHome = b;
158    }
159   
160    protected static LinkedList<CompilationHooks> globalHooksList = new LinkedList<>();
161    protected LinkedList<CompilationHooks> hooksList = new LinkedList<>(globalHooksList);
162
163    protected static LinkedList<CompilationStartListener> compilationStartListeners = new LinkedList<>();
164   
165    protected File tempDir = null;
166    protected File outDir = null;
167    protected File sourceDir = null;
168    protected File resourceDir = null;
169   
170    protected String[] targetPlatforms = null;
171    protected Collection<Problem> warnings = new ArrayList<Problem>();
172
173    private static final String OPTION_EXPORT_TEMPLATE = "==OPTIONS-LIST==";
174   
175    /**
176     * Basic export of all known problem types
177     */
178    public static class ProblemExporter {
179        public static void main(String ... args) {
180            ASTNode node = new ASTNode(); // Dummy read to initialize all of the producers
181            ProblemProducer.exportXML(new PrintStream(System.out));
182        }
183    }
184
185    public static OptionRegistry createOptions() {
186        return OptionRegistry.buildOptions();
187    }
188
189    public static ModulesSettings createModulesSettings(OptionRegistry options) {
190       return new ModulesSettings(options);
191    }
192
193    public ModelicaCompiler(OptionRegistry options) {
194        this.options = options;
195    }
196
197    protected ModelicaCompiler() {}
198
199    public CCompilerDelegator getCCompiler() {
200        String c_compiler = options.getStringOption(CCompilerDelegator.OPTION);
201        if (delegator == null || !c_compiler.equals(delegator_name)) {
202            delegator_name = c_compiler;
203            delegator = CCompilerDelegator.delegatorFor(c_compiler);
204        }
205        return delegator;
206    }
207   
208    public static <T extends CompilationHooks> T addGlobalCompilationHooks(T hooks) {
209        globalHooksList.add(hooks);
210        return hooks;
211    }
212   
213    public static void removeGlobalCompilationHooks(CompilationHooks hooks) {
214        globalHooksList.remove(hooks);
215    }
216   
217    public <T extends CompilationHooks> T addCompilationHooks(T hooks) {
218        hooksList.add(hooks);
219        return hooks;
220    }
221   
222    public void removeCompilationHooks(CompilationHooks hooks) {
223        hooksList.remove(hooks);
224    }
225
226    public static <T extends CompilationStartListener> T addCompilationStartListener(T listener) {
227        compilationStartListeners.add(listener);
228        return listener;
229    }
230
231    protected IErrorHandler errorHandler = null;
232   
233    /**
234     * Set the error handler to use for collection errors.
235     * Passing <code>null</code> resets to default.
236     */
237    public void setErrorHandler(IErrorHandler eh) {
238        errorHandler = eh;
239    }
240   
241    public IErrorHandler getErrorHandler() {
242        return errorHandler;
243    }
244
245    /**
246     * Notifies compilation start listeners that compilation will start.
247     */
248    protected static void notifyCompilationStart(ModelicaCompiler mc) {
249        for (CompilationStartListener listener : compilationStartListeners) {
250            listener.onCompileStart(mc);
251        }
252    }
253
254    /**
255     * Throws a {@link CompilationAbortedException} if any hooks class signals an abort.
256     */
257    private void hookCheckAbort() {
258        for (CompilationHooks hooks : hooksList) {
259            if (hooks.shouldAbort(this)) {
260                log.info("Compilation aborted.");
261                throw new CompilationAbortedException();
262            }
263        }
264    }
265   
266    /**
267     * Calls the hook to be called after the supplied code files are parsed.
268     */
269    private void hookFilesParsed(SourceRoot sr) {
270        for (CompilationHooks hooks : hooksList) {
271            hooks.filesParsed(this, sr);
272        }
273    }
274   
275    /**
276     * Calls the hook to be called after the error checks on the instantiated
277     * model are finished without errors.
278     */
279    private void hookModelInstantiated(InstClassDecl icd) {
280        for (CompilationHooks hooks : hooksList) {
281            hooks.modelInstantiated(this, icd);
282        }
283        icd.root().getUtilInterface().modelInstantiated(icd);
284    }
285   
286    /**
287     * Calls the hook to be called after the model is flattened.
288     */
289    private void hookModelFlattened(FClass fc) {
290        for (CompilationHooks hooks : hooksList) {
291            hooks.modelFlattened(this, fc);
292        }
293    }
294   
295    /**
296     * Calls the hook to be called after transformations are applied to the model.
297     */
298    private void hookModelTransformed(FClass fc) {
299        for (CompilationHooks hooks : hooksList) {
300            hooks.modelTransformed(this, fc);
301        }
302    }
303   
304    /**
305     * Calls the hook to be called after error checks of the flat model are
306     * finished without errors.
307     */
308    private void hookFlatModelChecked(FClass fc) {
309        for (CompilationHooks hooks : hooksList) {
310            hooks.flatModelChecked(this, fc);
311        }
312    }
313   
314    /**
315     * Calls the hook to be called after a code generator is created.
316     */
317    private void hookCodeGeneratorCreated(AbstractGenerator gen) {
318        for (CompilationHooks hooks : hooksList) {
319            hooks.codeGeneratorCreated(this, gen);
320        }
321    }
322   
323    /**
324     * Calls the hook to be called after output code is generated.
325     */
326    private void hookCodeGenerated(FClass fc, File dir) {
327        for (CompilationHooks hooks : hooksList) {
328            hooks.codeGenerated(this, fc, dir);
329        }
330    }
331   
332    /**
333     * Calls the hook to be called after the generated C code is compiled.
334     */
335    private void hookCodeCompiled() {
336        for (CompilationHooks hooks : hooksList) {
337            hooks.codeCompiled(this);
338        }
339    }
340
341    /**
342     * Calls the hook to be called before the FMU is packed.
343     * @param fc the source FClass
344     * @param dir the temporary FMU directory
345     */
346    private void hookPackFmu(FClass fc, File dir) {
347        for (CompilationHooks hooks : hooksList) {
348            hooks.packFmu(this, fc, dir);
349        }
350        fc.root().getUtilInterface().packFmu(fc, dir.toPath());
351    }
352   
353    /**
354     * Calls the hook to be called after the FMU is packed.
355     */
356    private void hookFmuPacked(FClass fc, File path) {
357        for (CompilationHooks hooks : hooksList) {
358            hooks.fmuPacked(this, fc, path);
359        }
360        fc.root().getUtilInterface().fmuPacked(fc, path.toPath());
361    }
362   
363    public String getStringOption(String key) throws UnknownOptionException {
364        return options.getStringOption(key);
365    }
366   
367    public void setStringOption(String key, String value) throws UnknownOptionException {
368        options.setStringOption(key,value);
369    }
370   
371    public int getIntegerOption(String key) throws UnknownOptionException {
372        return options.getIntegerOption(key);
373    }
374   
375    public void setIntegerOption(String key, int value) throws UnknownOptionException {
376        options.setIntegerOption(key, value);
377    }
378   
379    public double getRealOption(String key) throws UnknownOptionException {
380        return options.getRealOption(key);
381    }
382   
383    public void setRealOption(String key, double value) throws UnknownOptionException {
384        options.setRealOption(key, value);
385    }
386   
387    public boolean getBooleanOption(String key) throws UnknownOptionException{
388        return options.getBooleanOption(key);
389    }
390   
391    public void setBooleanOption(String key, boolean value) throws UnknownOptionException {
392        options.setBooleanOption(key, value);
393    }
394
395    public void setDiagnosticsGenerator(DiagnosticsGenerator diagGenerator) {
396        this.diagGenerator = diagGenerator;
397    }
398
399    public DiagnosticsGenerator getDiagnosticsGenerator() {
400        return this.diagGenerator;
401    }
402   
403    public String getOptionDescription(String key) throws UnknownOptionException {
404        return options.getDescription(key);
405    }
406   
407    public boolean willDumpMemoryUse() {
408        return dumpMemoryUse;
409    }
410
411    public void setDumpMemoryUse(boolean dump) {
412        dumpMemoryUse = dump;
413    }
414
415    public void setDumpMemoryUse(boolean dump, int minSize) {
416        dumpMemoryUse = dump;
417        dumpMemoryUseMinSize = minSize;
418    }
419
420    public void setDumpMemoryUse(boolean dump, String minSize) {
421        if (minSize == null || minSize.isEmpty())
422            setDumpMemoryUse(dump);
423        else
424            setDumpMemoryUse(dump, (int) ASTNode.parseMem(minSize));
425    }
426   
427    public boolean willFindFlatToInstanceLinks() {
428        return findFlatToInstanceLinks;
429    }
430
431    public void setFindFlatToInstanceLinks(boolean find) {
432        findFlatToInstanceLinks = find;
433    }
434
435    /**
436     * Returns the modelicapath attribute set for this compiler instance.
437     *
438     * @return Reference to the modelicapath attribute.
439     *
440     */
441    public String getModelicapath() {
442        return options.getStringOption("MODELICAPATH");
443    }
444   
445    /**
446     * Set the modelicapath attribute.
447     *
448     * @param path The new modelicapath.
449     */
450    public void setModelicapath(String path) {
451        options.setStringOption("MODELICAPATH", path);
452    }
453
454    protected final static int NUM_USED_MEMORY_SLOTS = 6;
455    protected long[] usedMem = new long[NUM_USED_MEMORY_SLOTS];
456    protected int numUsedMemFilled;
457    protected long timeCompilationStarted;
458
459    /**
460     * Initilize vars gathering debug information about compilation.
461     *
462     * Should be called before compilation process begins.
463     */
464    protected void resetCompilationInfo() {
465        timeCompilationStarted = System.currentTimeMillis();
466        numUsedMemFilled = 0;
467    }
468   
469    /**
470     * Log debug information about compilation.
471     *
472     * Should be called after compilation process ends.
473     */
474    protected void logCompilationInfo() {
475        long time = System.currentTimeMillis() - timeCompilationStarted;
476        double time2 = Math.round(time / 10.0) / 100.0;
477        log.debug("Compilation took " + time2 + " s");
478       
479        noteUsedMemory();  // Needed if an exception occurred
480        int numFinishedSteps = numUsedMemFilled / 2;
481        if (numFinishedSteps > 0) {
482            log.debug("Changes in memory use:");
483            logMemoryUseForStep("parseModel", 0);
484        }
485        if (numFinishedSteps > 1)
486            logMemoryUseForStep("instantiateModel", 1);
487        if (numFinishedSteps > 2)
488            logMemoryUseForStep("flattenModel", 2);
489    }
490   
491    /**
492     * Log memory change for a single compilation step.
493     *
494     * Called by {@link #logCompilationInfo()}.
495     *
496     * @param name   the name of the step
497     * @param index  the index of the step (0-2)
498     */
499    protected void logMemoryUseForStep(String name, int index) {
500        String mem = ASTNode.formatMem((int) (usedMem[2 * index + 1] - usedMem[2 * index]));
501        log.debug(String.format(" %-19s %8s", name + "():", mem));
502    }
503   
504    /**
505     * Saves away the current amount of memory used.
506     */
507    protected void noteUsedMemory() {
508        if (numUsedMemFilled < NUM_USED_MEMORY_SLOTS)
509            usedMem[numUsedMemFilled++] = getUsedMemory();
510    }
511   
512    private static final Runtime RUNTIME = Runtime.getRuntime();
513   
514    /**
515     * Get the amount of memory currently used.
516     *
517     * This includes objects that are no longer reachable but not yet garbage collected.
518     */
519    public static long getUsedMemory() {
520        return RUNTIME.totalMemory() - RUNTIME.freeMemory();
521    }
522
523    /**
524     * Save a dump of the memory use of an AST.
525     *
526     * The dump will be saved in a file named <code>"size_" + type + ".txt"</code>.
527     *
528     * @param root   the root of the AST to dump memory use for
529     * @param type   a one-word description of the tree to dump
530     * @param count  it node counts should also be generated
531     */
532    protected void dumpMemoryUseFile(ASTNode root, UtilInterface util, String type, boolean count) throws FileNotFoundException {
533        dumpMemoryUseFile(root, util, type, type, count);
534    }
535
536    /**
537     * Save a dump of the memory use of an AST.
538     *
539     * The dump will be saved in a file named <code>"size_" + name + ".txt"</code>.
540     *
541     * @param root   the root of the AST to dump memory use for
542     * @param type   a short description of the tree to dump
543     * @param name   the variable part of the file name
544     * @param count  it node counts should also be generated
545     */
546    protected void dumpMemoryUseFile(ASTNode root, UtilInterface util, String type, String name, boolean count)
547            throws FileNotFoundException {
548        if (dumpMemoryUse) {
549            String file = "size_" + name + ".txt";
550            log.debug("Dumping " + type + " tree to '" + file + "'...");
551            long time = System.currentTimeMillis();
552            root.dumpMemoryUse(file, true, -1, dumpMemoryUseMinSize);
553            time = Math.round((System.currentTimeMillis() - time) / 1000.0);
554            if (count)
555                root.buildNodeCount(util.getBuildNodeCountMap());
556            log.debug(" Dumped tree in " + time + "s");
557        }
558    }
559
560    /**
561     * Save a dump of the node class counts of an AST (or several).
562     *
563     * The dump will be saved in a file named <code>"node_count.txt"</code>.
564     */
565    protected void dumpNodeCountFile(Root root)
566            throws IOException {
567        if (dumpMemoryUse) {
568            String file = "node_count.txt";
569            log.debug("Dumping node counts to '" + file + "'...");
570            root.dumpNodeCount(file, root.getUtilInterface());
571        }
572    }
573
574    /**
575     * Find any links from the flat tree to the instance tree.
576     */
577    protected void findFlatToInstanceLinks(FClass fc) {
578        if (findFlatToInstanceLinks) {
579            log.warning("Searching memory graph for flat tree for links to instance tree...");
580            new MemorySpider(new MemorySpider.ClassFilteredVisitor<InstRoot>(InstRoot.class) {
581                protected void visitFiltered(InstRoot ir, Stack<MemorySpider.Frame> path) {
582                    Root root = null;
583                    int first = -1;
584                    int last = -1;
585                    for (int i = 0; last < 0 && i < path.size(); i++) {
586                        Object obj = path.get(i).getObject();
587                        if (obj instanceof BaseNode) {
588                            BaseNode n = (BaseNode) obj;
589                            try {
590                                if (first < 0) {
591                                    root = n.root();
592                                    first = i;
593                                } else if (root != n.root()) {
594                                    last = i;
595                                } else {
596                                    first = i;
597                                }
598                            } catch (Exception e) {}
599                        }
600                    }
601                    log.error("Found link to instance tree, starting at: " + path.get(first).name());
602                    for (int i = first + 1; i <= last; i++)
603                        log.error("  " + path.get(i));
604                    throw new IllegalArgumentException();
605                }
606            }).traverse(fc);
607            log.warning("Done.");
608        }
609    }
610   
611    private static Path[] stringsToPaths(String[] s) {
612        Path paths[] = new Path[s.length];
613        for (int i = 0; i < s.length; i++) {
614            paths[i] = Paths.get(s[i]);
615        }
616        return paths;
617    }
618   
619    /**
620     * Creates a target object.
621     *
622     * @param target The type of target: me, cs, ect. Use nocodegen for a NOCODEGEN target.
623     * @param version The version in case of an fmu. Use null for a NOCODEGEN.
624     */
625    public TargetObject createTargetObject(String target, String version) {
626        return TargetObject.getTarget(target, version);
627    }
628
629    /**
630     * Compiles a model and creates an FMU, convenience method for compileUnit that uses default version.
631     * <p>
632     * Compiles a model (parsing, instantiating, flattening, code generation and
633     * binary file compilation) and packs the result in an FMU.
634     *
635     * @param className name of model class in the model file to compile.
636     * @param fileName  array of model file or library paths.
637     * @param target    the compiler target. Valid options are 'me' or 'cs'.
638     * @param compileTo specify location of the compiled FMU. If a file is specified, the model will be renamed to this
639     *                  name during the compilation. If directory is specified, the model will keep its original name.
640     * @return          a {@link CompiledUnit} result object.
641     * @deprecated      Use {@link #compileFMU(String, Path[], String, Path)} instead
642     */
643    @Deprecated
644    public CompiledUnit compileFMU(String className, String fileName[], String target, String compileTo) 
645            throws ModelicaException, FileNotFoundException, IOException, beaver.Parser.Exception {
646
647        return compileFMU(className, stringsToPaths(fileName), target, compileTo == null ? null : Paths.get(compileTo));
648    }
649   
650    /**
651     * Compiles a model and creates an FMU, convenience method for compileUnit that uses default version.
652     * <p>
653     * Compiles a model (parsing, instantiating, flattening, code generation and
654     * binary file compilation) and packs the result in an FMU.
655     *
656     * @param className name of model class in the model file to compile.
657     * @param paths     array of model file or library paths.
658     * @param target    the compiler target. Valid options are 'me' or 'cs'.
659     * @param compileTo specify location of the compiled FMU. If a file is specified, the model will be renamed to this
660     *                  name during the compilation. If directory is specified, the model will keep its original name.
661     * @return          a {@link CompiledUnit} result object.
662     * @deprecated      Use {@link #compileFMU(String, Path[], String, Path)} instead
663     */
664    public CompiledUnit compileFMU(String className, Path paths[], String target, Path compileTo)
665            throws ModelicaException, FileNotFoundException, IOException, beaver.Parser.Exception {
666   
667        return compileUnit(className, paths, target, "1.0" , compileTo);
668    }
669
670    /**
671     * Compiles a model and creates an FMUX, convenience method for compileUnit.
672     * <p>
673     * Compiles a model (parsing, instantiating, flattening and XML code
674     * generation) and packs the result in an FMUX.
675     *
676     * @param className name of model class in the model file to compile.
677     * @param fileName  array of model file or library paths.
678     * @param compileTo specify location of the compiled FMUX. If a file is specified, the model will be renamed to this
679     *                  name during the compilation. If directory, the  model will keep its original name.
680     * @return          a {@link CompiledUnit} result object.
681     * @deprecated      Use {@link #compileFMUX(String, Path[], Path)} instead
682     */
683    @Deprecated
684    public CompiledUnit compileFMUX(String className, String fileName[], String compileTo) 
685            throws ModelicaException, FileNotFoundException, IOException, beaver.Parser.Exception {
686
687        return compileFMUX(className, stringsToPaths(fileName), compileTo == null ? null : Paths.get(compileTo));
688    }
689
690    /**
691     * Compiles a model and creates an FMUX, convenience method for compileUnit.
692     * <p>
693     * Compiles a model (parsing, instantiating, flattening and XML code
694     * generation) and packs the result in an FMUX.
695     *
696     * @param className name of model class in the model file to compile.
697     * @param fileName  array of model file or library paths.
698     * @param compileTo specify location of the compiled FMUX. If a file is specified, the model will be renamed to this
699     *                  name during the compilation. If directory, the  model will keep its original name.
700     * @return          a {@link CompiledUnit} result object.
701     */
702    public CompiledUnit compileFMUX(String className, Path fileName[], Path compileTo) 
703            throws ModelicaException, FileNotFoundException, IOException, beaver.Parser.Exception {
704
705        return compileUnit(className, fileName, "fmux", null , compileTo);
706    }
707    /**
708     * Compiles an FMU or FMUX. Is a wrapper.
709     * <p>
710     * Compiles a model (parsing, instantiating, flattening, code generation and
711     * binary file compilation) and packs the result in an FMU/FMUX.
712     *
713     * @param className name of model class in the model file to compile.
714     * @param fileName  array of model file or library paths.
715     * @param target    the compiler target. Valid options are 'me' or 'cs'.
716     * @param version   the FMI version. Valid options are '1.0' or '2.0'.
717     * @param compileTo specify location of the compiled FMU/FMUX. If a file is specified, the model will be renamed to
718     *                  this name during the compilation. If directory, the  model will keep its original name.
719     * @return          a {@link CompiledUnit} result object.
720     * @deprecated      Use {@link #compileUnit(String, Path[], String, String, String)} instead.
721     */
722    @Deprecated
723    public CompiledUnit compileUnit(String className, String fileName[], String target, String version, String compileTo) 
724            throws ModelicaException, FileNotFoundException, IOException, beaver.Parser.Exception {
725
726        return compileUnit(className, stringsToPaths(fileName), target, version, compileTo == null ? null : Paths.get(compileTo));
727    }
728   
729    /**
730     * Compiles an FMU or FMUX. Is a wrapper.
731     * <p>
732     * Compiles a model (parsing, instantiating, flattening, code generation and
733     * binary file compilation) and packs the result in an FMU/FMUX.
734     *
735     * @param className name of model class in the model file to compile.
736     * @param fileName  array of model file or library paths.
737     * @param target    the compiler target. Valid options are 'me' or 'cs'.
738     * @param version   the FMI version. Valid options are '1.0' or '2.0'.
739     * @param compileTo specify location of the compiled FMU/FMUX. If a file is specified, the model will be renamed to
740     *                  this name during the compilation. If directory, the  model will keep its original name.
741     * @return          a {@link CompiledUnit} result object.
742     */
743    public CompiledUnit compileUnit(String className, Path fileName[], String target, String version, Path compileTo) 
744            throws ModelicaException, FileNotFoundException, IOException, beaver.Parser.Exception {
745
746        TargetObject targetObject = TargetObject.getTarget(target, version);
747        return compileUnit(className, fileName, targetObject, compileTo);
748    }
749
750    /**
751     * Compiles an FMU or FMUX.
752     *
753     * @param className name of model class in the model file to compile.
754     * @param fileName  array of model file or library paths.
755     * @param target    target object, contains information about the target, its unit suffix for example.
756     * @param compileTo specify location of the compiled FMU/FMUX. If a file is specified, the model will be renamed to
757     *                  this name during the compilation. If directory, the  model will keep its original name.
758     * @return          a {@link CompiledUnit} result object.
759     */
760    protected CompiledUnit compileUnit(String className, Path fileName[], TargetObject target, Path compileTo) 
761            throws ModelicaException, FileNotFoundException, IOException, beaver.Parser.Exception {
762
763        /*
764         * Always set certain options when compiling.
765         * First save these options in the temporary options' registry to reset when compiling has finished.
766         */
767        OptionRegistry tempOptions = options.copy();
768
769        /*
770         * Set options for the target.
771         */
772        target.setDefaultOptions(options);
773
774        boolean doTearDown = true;
775        try {
776            doTearDown = trySetUp();
777            return doCompileUnit(className, fileName, target, compileTo);
778        } finally {
779            deleteOutDir();
780            tryTearDown(doTearDown);
781
782            /*
783             * Reset all options.
784             */
785            options.copyAllOptions(tempOptions);
786        }
787    }
788
789    protected CompiledUnit doCompileUnit(String className, Path fileName[], TargetObject target, Path compileTo) 
790        throws ModelicaException, FileNotFoundException, IOException, beaver.Parser.Exception {
791
792        CompiledUnit unit = null;
793        try {
794            StepInfo.GC_BEFORE_MEM = options.getBooleanOption("debug_invoke_gc");
795
796            if (outDir == null) {
797                setRandomOutDir();
798            }
799
800            if (target.getMakeFileFlag() != null) {
801                // Might be used by constant evaluation.
802                CCompilerDelegator ccompiler = getCCompiler();
803                ccompiler.setTargetPlatforms(targetPlatforms);
804
805                // Get loadable module settings.
806                ModulesSettings modulesSettings = createModulesSettings(options);
807                ccompiler.setModuleLibraryNames(modulesSettings.getLibraryNames());
808            }
809
810            /*
811             * Compile mo-file and generate code for all templates that are not null.
812             */
813            FClass fc = compileModel(fileName, className, target, compileTo);
814
815            if (!target.getCodeGenFlag()) {
816                /*
817                 * No code has been generated.
818                 */
819                return null;
820            }
821
822            /*
823             * Compile C code if the Makefile flag is not null.
824             */
825            hookCheckAbort();
826            doCompileCCode(target, fc);
827
828            /*
829             * Package unit.
830             */
831            ASTNode.beginStep("packUnit()");
832            Path unitPath = packUnit(className, target, fc);
833            unit = log.logCompiledUnit(unitPath, warnings, fc.numberOfComponents());
834            ASTNode.endStep("packUnit()");
835
836        } finally {
837            log.debug("Time usage and memory usage change during compilation steps:");
838            ASTNode.getStepInfo().logReport();
839            if (options.getBooleanOption("debug_csv_step_info"))
840                ASTNode.getStepInfo().writeCSVFile(new File(FClass.removeModifiersFromClassName(className) + ".csv"));
841        }
842       
843        return unit;
844    }
845
846    protected void parseFiles(Path[] paths) throws IOException {
847        StepInfo.TimeItem time = new StepInfo.TimeItem();
848        time.begin();
849        parseFiles(Arrays.asList(paths), true);
850        time.end();
851        log.info("Total time: " + time);
852    }
853
854    private void parseFiles(Iterable<Path> files, boolean all) throws IOException {
855        for (Path file : files) {
856            if (Files.isDirectory(file)) {
857                try(DirectoryStream<Path> ds = Files.newDirectoryStream(file)) { 
858                    parseFiles(ds, false);
859                }
860            } else {
861                String path = file.toString();
862                try {
863                    if (all || hasModelicaFileExt(path)) {
864                        parseModel(file);
865                        log.info(file + " parsed OK.");
866                    }
867                } catch (CompilerException e) {
868                    log.logCompilerException(e);
869                } catch (FileNotFoundException e) {
870                    log.error("Could not find file: " + e.getMessage());
871                } catch (IOException e) {
872                    log.error("Error opening file: " + e.getMessage());
873                } catch (Exception e) {
874                    log.error("Parser thew an exception on file " + path + ":\n" + e);
875                }
876            }
877        }
878    }
879   
880    public boolean hasModelicaFileExt(String file) {
881        return file.endsWith(".mo");
882    }
883
884    private static final int ZIP_BUFFER_SIZE = 2048;
885   
886
887    /**
888     * Write all files in a directory and its subdirectories to a zip stream.
889     *
890     * @param dir     directory to zip
891     * @param out     zip stream to write to
892     */
893    protected void zipDir(File dir, ZipOutputStream out) {
894        zipDir(dir, out, null);
895    }
896
897    /**
898     * Write all files in a directory and its subdirectories to a zip stream.
899     *
900     * @param dir     directory to zip
901     * @param out     zip stream to write to
902     * @param zipDir  directory within the zip file to write to, or <code>null</code> for the root
903     */
904    protected void zipDir(File dir, ZipOutputStream out, File zipDir) {
905        zipDir(dir, out, zipDir, new byte[ZIP_BUFFER_SIZE]);
906    }
907   
908    /**
909     * Write all files in a directory and its subdirectories to a zip stream.
910     *
911     * @param dir     directory to zip
912     * @param out     zip stream to write to
913     * @param zipDir  directory within the zip file to write to, or <code>null</code> for the root
914     * @param buffer  buffer to use when writing files
915     */
916    private void zipDir(File dir, ZipOutputStream out, File zipDir, byte[] buffer) {
917        for (File f : dir.listFiles()) {
918            File fz = new File(zipDir, f.getName());
919            try {
920                if (f.isDirectory()) {
921                    out.putNextEntry(new ZipEntry(fz.getPath() + "/"));
922                    zipDir(f, out, fz, buffer);
923                } else {
924                    FileInputStream in = new FileInputStream(f);
925                    out.putNextEntry(new ZipEntry(fz.getPath()));
926                    for (int n; (n = in.read(buffer, 0, buffer.length)) != -1; ) 
927                        out.write(buffer, 0, n);
928                    in.close();
929                }
930            } catch (FileNotFoundException e) {
931                // Should only occur in weird cases - ignore and skip this file
932            } catch (IOException e) {
933                // TODO: this should result in an error message about failing to zip file
934                e.printStackTrace();
935            }
936        }
937    }
938
939    /**
940     * Parses a model and returns a reference to the root of the source tree.
941     * Options related to the compilation are also loaded here and added to the
942     * source tree representation.
943     *
944     * @param name
945     *            The name of the model file.
946     *
947     * @return The root of the source tree.
948     *
949     * @throws beaver.Parser.Exception
950     *             If there was an Beaver parsing exception.
951     * @throws CompilerException
952     *             If errors have been found during the parsing.
953     * @throws FileNotFoundException
954     *             If the model file can not be found.
955     * @throws IOException
956     *             If there was an error reading the model file. (Beaver exception.)
957     */
958    private SourceRoot parseModel(Path name) 
959      throws FileNotFoundException, IOException, beaver.Parser.Exception, CompilerException{
960        return parserHandler.parseModel(createUtilInterface(), LoadInfo.create(name));
961    }
962
963    /**
964     *
965     * Parses a set of files and returns a reference to the root of a source tree
966     * where the content of all files is contained. Each file is parsed using
967     * the parseModel method.
968     *
969     * @param files
970     *            An array of file names.
971     *
972     * @return The root of the source tree.
973     *
974     * @throws beaver.Parser.Exception
975     *             If there was a Beaver parsing exception.
976     * @throws CompilerException
977     *             If errors have been found during the parsing.
978     * @throws FileNotFoundException
979     *             If any of the model files could not be found.
980     * @throws IOException
981     *             If there was an error reading any of the model files. (Beaver exception.)
982     * @deprecated use {@link #parseModelFromPaths(Path[])} instead
983     */
984    @Deprecated
985    public SourceRoot parseModel(String[] files)
986      throws FileNotFoundException, IOException, beaver.Parser.Exception, CompilerException {
987        // NB: This method is called by compile_wrappers.py! It may not be deleted!
988        return parseModelFromPaths(stringsToPaths(files));
989    }
990
991    /**
992     * Parses a set of files and returns a reference to the root of a source tree
993     * where the content of all files is contained. Each file is parsed using
994     * the {@link #doParseModel}.
995     *
996     * @param files
997     *            An array of file paths.
998     *
999     * @return The root of the source tree.
1000     *
1001     * @throws beaver.Parser.Exception
1002     *             If there was a Beaver parsing exception.
1003     * @throws CompilerException
1004     *             If errors have been found during the parsing.
1005     * @throws FileNotFoundException
1006     *             If any of the model files could not be found.
1007     * @throws IOException
1008     *             If there was an error reading any of the model files. (Beaver exception.)
1009     */
1010    public SourceRoot parseModelFromPaths(Path[] files)
1011      throws FileNotFoundException, IOException, beaver.Parser.Exception, CompilerException {
1012        hookCheckAbort();
1013        boolean doTearDown = true;
1014        try {
1015            doTearDown = trySetUp();
1016            Collection<LoadInfo> loadInfos = new ArrayList<>();
1017            for (Path path : files) {
1018                loadInfos.add(LoadInfo.create(path));
1019            }
1020            return doParseModel(loadInfos);
1021        } finally {
1022            tryTearDown(doTearDown);
1023        }
1024    }
1025
1026    /**
1027     * Parses a string and returns a reference to the root of the source tree.
1028     * Options related to the compilation are also loaded here and added to the
1029     * source tree representation.
1030     *
1031     * @param code
1032     *            Modelica code to parse.
1033     * @param name
1034     *            The filename (or other description) to use when reporting errors.
1035     *
1036     * @return The root of the source tree.
1037     *
1038     * @throws beaver.Parser.Exception
1039     *             If there was an Beaver parsing exception.
1040     * @throws CompilerException
1041     *             If errors have been found during the parsing.
1042     * @throws IOException
1043     *             If there was an error reading the model file. (Beaver exception.)
1044     */
1045    public SourceRoot parseString(String code, String name) 
1046      throws IOException, beaver.Parser.Exception, CompilerException {
1047        checkSetUp();
1048        return parserHandler.parseString(createUtilInterface(), code, LoadInfo.create(name));
1049    }
1050
1051    public SourceRoot doParseModel(Collection<LoadInfo> loadInfos) 
1052      throws FileNotFoundException, IOException, beaver.Parser.Exception, CompilerException {
1053        checkSetUp();
1054        notifyCompilationStart(this);
1055        ASTNode.getStepInfo().reset();
1056        ASTNode.beginStep("parseModel()");
1057        SourceRoot sr = parserHandler.parseModel(createUtilInterface(), loadInfos);
1058        hookFilesParsed(sr);
1059        ASTNode.endStep("parseModel()");
1060       
1061        return sr;
1062    }
1063   
1064    /**
1065     * Parses and instantiated the model <code>cl</code> from the source files <code>name</code>.
1066     *
1067     * @param paths
1068     *            Array of model file or library paths.
1069     * @param cl
1070     *            The name of the class in the model file to compile.
1071     * @param target
1072     *            The model represenation type the model should be compiled to.
1073     *
1074     * @throws ModelicaException
1075     *             If errors have been found during the parsing, instantiation
1076     *             or flattening.
1077     * @throws FileNotFoundException
1078     *             If the model file can not be found.
1079     * @throws IOException
1080     *             If there was an error creating the .mof file.
1081     * @throws beaver.Parser.Exception
1082     *             If there was an Beaver parsing exception.
1083     */
1084    private InstClassDecl instantiateModel(Path[] paths, String cl, TargetObject target)
1085            throws ModelicaException, FileNotFoundException, IOException, beaver.Parser.Exception {
1086        // build source tree
1087        SourceRoot sr = parseModelFromPaths(paths);
1088        dumpMemoryUseFile(sr, sr.getUtilInterface(), "source", false);
1089
1090        if (options.getBooleanOption("generate_html_diagnostics")) {
1091            setDiagnosticsGenerator(new DiagnosticsGenerator(cl, options));
1092        }
1093
1094        // compute instance tree
1095        InstClassDecl icl = instantiateModel(sr, cl, target);
1096       
1097        dumpMemoryUseFile(sr, sr.getUtilInterface(), "source and instance", "instance", true);
1098       
1099        return icl;
1100    }
1101
1102    /**
1103     * Computes a model instance tree from a source tree. Some error checks such
1104     * as type checking is performed during the computation.
1105     *
1106     * @param sr
1107     *            The reference to the model source root.
1108     * @param cl
1109     *            The name of the class in the model file to compile.
1110     * @param target
1111     *            The model represenation type the model should be compiled to.
1112     *
1113     * @return The instance node corresponding to the instantiated model.
1114     *
1115     * @throws CompilerException
1116     *             If errors have been found during the instantiation.
1117     * @throws ModelicaClassNotFoundException
1118     *             If the Modelica class to instantiate is not found.
1119     */
1120    public InstClassDecl instantiateModel(SourceRoot sr, String cl, TargetObject target) 
1121        throws ModelicaClassNotFoundException, CompilerException {
1122        hookCheckAbort();
1123        boolean doTearDown = true;
1124        try {
1125            doTearDown = trySetUp(sr.getErrorHandler());
1126            return doInstantiateModel(sr, cl, target);
1127        } finally {
1128            tryTearDown(doTearDown);
1129        }
1130    }
1131   
1132    public InstClassDecl doInstantiateModel(SourceRoot sr, String cl, TargetObject target) 
1133        throws ModelicaClassNotFoundException, CompilerException {
1134       
1135        ASTNode.beginStep("instantiateModel()");
1136       
1137        InstProgramRoot ipr = sr.getProgram().getInstProgramRoot();
1138       
1139        log.info("Checking for errors...");
1140        InstClassDecl icd = ipr.instantiateModel(cl);
1141        try {
1142            icd.checkErrorsInModelInstance(cl, target.getCheckType());
1143        } finally {
1144            handleCompilerWarnings(sr.collectWarnings());
1145        }
1146       
1147        hookModelInstantiated(icd);
1148        ASTNode.endStep("instantiateModel()");
1149       
1150        return icd;
1151    }
1152
1153    protected void handleCompilerWarnings(Collection<Problem> warnings) throws CompilerException {
1154        if (options.getBooleanOption("generate_html_diagnostics") && getDiagnosticsGenerator() != null) 
1155            getDiagnosticsGenerator().writeProblems(warnings);
1156       
1157        if (!warnings.isEmpty()) {
1158            log.logProblems(warnings);
1159            this.warnings.addAll(warnings);
1160        }
1161    }
1162   
1163    /**
1164     * Retrieves a list of warnings and clear the internal list.
1165    */
1166    public Problem[] retrieveAndClearWarnings() {
1167        Problem[] oldWarnings = warnings.toArray(new Problem[warnings.size()]);
1168        warnings = new ArrayList<Problem>();
1169        return oldWarnings;
1170    }
1171
1172    /**
1173     * Please use the correctly spelled version!
1174     */
1175    @Deprecated
1176    public Problem[] retreiveAndClearWarnings() {
1177        return retrieveAndClearWarnings();
1178    }
1179
1180    /**
1181     * Computes the flattened model representation from a model instance.
1182     *
1183     * @param icd
1184     *            A reference to the model instance node.
1185     * @param target
1186     *            The model represenation type the model should be compiled to.
1187     * @param flatName
1188     *            Name of the unit/flat model supplied by the user, if any.
1189     *
1190     * @return FClass object representing the flattened model.
1191     *
1192     * @throws CompilerException
1193     *             If errors have been found during the flattening.
1194     * @throws IOException
1195     *             If there was an error creating the .mof file.
1196     * @throws ModelicaClassNotFoundException
1197     *             If the Modelica class to flatten is not found.
1198     */
1199    public FClass flattenModel(InstClassDecl icd, TargetObject target, String flatName) 
1200            throws CompilerException, ModelicaClassNotFoundException, IOException {
1201        hookCheckAbort();
1202        boolean doTearDown = true;
1203        try {
1204            doTearDown = trySetUp(icd.root().getErrorHandler());
1205            PassAndForget<InstClassDecl> buf = new PassAndForget<InstClassDecl>(icd);
1206            icd = null;
1207            return doFlattenModel(buf.pass(), target, flatName);
1208        } finally {
1209            tryTearDown(doTearDown);
1210        }
1211    }
1212   
1213    public FClass doFlattenModel(InstClassDecl icd, TargetObject target, String flatName) 
1214            throws CompilerException, ModelicaClassNotFoundException, IOException {
1215        ASTNode.beginStep("flattenModel()");
1216       
1217        String instName = icd.qualifiedName();
1218        File flatFile = new File(sourceDir, (flatName == null ? instName : flatName) + ".mof");
1219        final FClass fc = FClass.create(icd, flatName);
1220       
1221        ASTNode.beginStep("flatten()");
1222        log.info("Flattening model...");
1223        icd.flattenInstClassDecl(fc);
1224        dumpMemoryUseFile(fc, fc.root().getUtilInterface(), "flat", true);
1225        dumpNodeCountFile(icd.root());
1226        icd = null;
1227        ASTNode.endStep("flatten()");
1228       
1229        findFlatToInstanceLinks(fc);
1230        hookModelFlattened(fc);
1231        hookCheckAbort();
1232
1233        OptionRegistry options = fc.myOptions();
1234       
1235        // Output the untransformed flattened model
1236        ASTNode.beginStep("prettyPrintRawFlat()");
1237        if (options.getBooleanOption("generate_mof_files")) {
1238            log.debug("Creating raw .mof file...");
1239            CodeStream out = new CodeStream(flatFile);
1240            fc.prettyPrint_MC(out, "");
1241            out.close();
1242            log.debug("... raw .mof file created.");
1243        }
1244
1245        log.verbose("Raw flattened model:");
1246        log.verbose(fc);
1247        ASTNode.endStep("prettyPrintRawFlat()");
1248
1249        if (options.getBooleanOption("generate_html_diagnostics") && getDiagnosticsGenerator()!=null) {
1250            ASTNode.beginStep("htmlDiagnostics()");
1251            getDiagnosticsGenerator().writeRawFlattenedModel(fc);
1252            getDiagnosticsGenerator().setModelDiagnosticsBeforeTransform(fc.modelDiagnostics());
1253            ASTNode.endStep("htmlDiagnostics()");
1254        }
1255       
1256        fc.transformCanonical();
1257       
1258        /* Temporary fix to problems with long compilation times due to later evaluations */
1259        getExternalFunctionCache().tearDown();
1260        options.external_constant_evaluation.setValue(0);
1261       
1262        hookModelTransformed(fc);
1263        hookCheckAbort();
1264       
1265        ASTNode.beginStep("prettyPrintFlat()");
1266        if (options.getBooleanOption("generate_mof_files")) {
1267            log.debug("Creating transformed .mof file...");
1268            CodeStream out = new CodeStream(new File(sourceDir, instName + "_transformed.mof"));
1269            fc.prettyPrint_MC(out, "");
1270            out.close();
1271            log.debug("... transformed .mof file created.");
1272        }
1273       
1274        log.verbose("Diagnostics for transformed flattened model:");
1275        log.verbose(new Object() {
1276            public String toString() {
1277                return fc.diagnostics();
1278            };
1279        });
1280       
1281        log.verbose("Transformed flattened model:");
1282        log.verbose(fc);
1283       
1284        ASTNode.endStep("prettyPrintFlat()");
1285       
1286        dumpMemoryUseFile(fc, fc.root().getUtilInterface(), "transformed", false);
1287       
1288        if (options.getBooleanOption("write_iteration_variables_to_file")) {
1289            ASTNode.beginStep("writeIterationVariables()");
1290            if (!fc.onlyInitBLT())
1291                fc.getDAEBLT().writeIterationVariablesToFile(new File(resourceDir, instName + "_iteration_variables.txt"));
1292            fc.getDAEInitBLT().writeIterationVariablesToFile(new File(resourceDir, instName + "_initial_system_iteration_variables.txt"));
1293            ASTNode.endStep("writeIterationVariables()");
1294        }
1295
1296        if (options.getBooleanOption("write_tearing_pairs_to_file")) {
1297            ASTNode.beginStep("writeIterationVariables()");
1298            if (!fc.onlyInitBLT())
1299                fc.getDAEBLT().writeTearingPairsToFile(new File(instName + "_tearing_pairs.txt"));
1300            fc.getDAEInitBLT().writeTearingPairsToFile(new File(instName + "_initial_system_tearing_pairs.txt"));
1301            ASTNode.endStep("writeIterationVariables()");
1302        }
1303
1304        fc.errorCheck(target.getCheckType());
1305        handleCompilerWarnings(fc.collectWarnings());
1306
1307        if (options.getBooleanOption("generate_html_diagnostics") && getDiagnosticsGenerator()!=null) {
1308            ASTNode.beginStep("htmlDiagnostics()");
1309            getDiagnosticsGenerator().writeTransformedFlattenedModel(fc);
1310            getDiagnosticsGenerator().writeDiagnostics(fc);
1311            ASTNode.endStep("htmlDiagnostics()");
1312        }
1313
1314        hookFlatModelChecked(fc);
1315        ASTNode.endStep("flattenModel()");
1316
1317        return fc;
1318    }
1319
1320    /**
1321     * Create a new CGenerator object.
1322     *
1323     * Override for subclasses needing another subclass of CGenerator.
1324     */
1325    protected CGenerator createCGenerator(FClass fc) {
1326        return new CGenerator(ASTNode.prettyPrinter, '$', fc);
1327    }
1328
1329    protected ExternCEvalGenerator createCGenerator(FExternalStmt ext) {
1330        CodeGenContext cgc = new CodeGenContext().createProxy();
1331        Map<String,String> tempMap = new HashMap<String,String>();
1332        return new ExternCEvalGenerator(ASTNode.prettyPrinter, '$', null, ext, cgc, tempMap);
1333    }
1334
1335    /**
1336     *
1337     * Generates XML and c code for a flattened model represented as an instance
1338     * of FClass using template files. The XML variables, XML values and c files
1339     * are given the default names <modelname>.xml, <modelname>_values.xml and
1340     * <modelname>.c respectively.
1341     *
1342     * @param fc
1343     *            The FClass instance for which the code generation should be
1344     *            computed.
1345     * @param target
1346     *            The target object for the compiler.
1347     * @throws FileNotFoundException
1348     *             If either of the three template files can not be found.
1349     */
1350    public void generateCode(FClass fc, TargetObject target) throws FileNotFoundException {
1351        boolean doTearDown = true;
1352        try {
1353            doTearDown = trySetUp(fc.root().getErrorHandler());
1354            doGenerateCode(fc, target);
1355        } finally {
1356            tryTearDown(doTearDown);
1357        }
1358    }
1359   
1360    public void doGenerateCode(FClass fc, TargetObject target) throws FileNotFoundException {
1361        ASTNode.beginStep("generateCode()");
1362        log.info("Generating code...");
1363       
1364        String name = fc.nameUnderscore();
1365        Templates templates = target.getTemplates(getOptions());
1366       
1367        generateAllFiles(fc, target, templates, name);
1368        hookCodeGenerated(fc, outDir);
1369       
1370        fc.guidManager().setSourceFile(new File(outDir, "modelDescription.xml"));
1371        fc.guidManager().processDependentFiles();
1372       
1373        log.debug("... code generated.");
1374        ASTNode.endStep("generateCode()");
1375    }
1376   
1377    /**
1378     * Set the default logger and default level.
1379     */
1380    public void setDefaultLogger() {
1381        try {
1382            setLogger(DEFAULT_LEVEL + "|stdout");
1383        } catch (IllegalLogStringException e) {
1384            e.printStackTrace(); // Should never happen unless someone made major bobo!
1385        }
1386    }
1387   
1388    /**
1389     * Configure logging according to <code>logString</code>.
1390     */
1391    public void setLogger(String logString) throws IllegalLogStringException {
1392        setLogger(ModelicaLogger.createModelicaLoggersFromLogString(logString));
1393    }
1394   
1395    /**
1396     * Change logger to <code>logger</code>
1397     */
1398    public void setLogger(ModelicaLogger logger) {
1399        log.close();
1400        log = logger;
1401        ASTNode.log = log;
1402    }
1403   
1404    public ModelicaLogger log() {
1405        return log;
1406    }
1407   
1408    /**
1409     * Close and disconnect all loggers.
1410     */
1411    public void closeLogger() {
1412        log.close();
1413    }
1414
1415    private void setOptions(Arguments programarguments) {
1416        // Create option registry
1417        options = createOptions();
1418        String opts = programarguments.get("opt");
1419        if (opts != null) {
1420            for (String opt : opts.split(",")) {
1421                String[] parts = opt.split(":", 2);
1422                if (parts.length == 1)
1423                    options.setBooleanOption(parts[0], true);
1424                else
1425                    options.setOption(parts[0], parts[1]);
1426            }
1427        }
1428       
1429        //add modelicapath to optionregistry
1430        String modelicapath = programarguments.get("modelicapath");
1431        if (modelicapath == null) {
1432            //modelicapath was not set in program arguments -> check envir variable or via JMODELICA_HOME
1433            if (System.getenv("MODELICAPATH") != null) 
1434                modelicapath = System.getenv("MODELICAPATH");
1435            else
1436                modelicapath = EnvironmentUtils.getThirdPartyMSL().toString();
1437        }
1438        options.setStringOption("MODELICAPATH", modelicapath);
1439    }
1440   
1441    public OptionRegistry getOptions() {
1442        return options;
1443    }
1444
1445    public static final String COMPILER_VERSION = Version.parseVersion();
1446
1447    protected void setArguments(Arguments programarguments) {
1448       
1449        int arg = 0;
1450        String modelicapath = null;
1451       
1452        //log option
1453        try {
1454            String logString = programarguments.get("log");
1455            setLogger(logString);
1456        } catch (IllegalLogStringException e) {
1457            setLogger(e.getLogger());
1458            log.error(e);
1459            closeLogger();
1460            System.exit(1);
1461        }
1462       
1463        setDumpMemoryUse(programarguments.containsKey("dumpmemuse"), programarguments.get("dumpmemuse"));
1464        setFindFlatToInstanceLinks(programarguments.containsKey("findflatinst"));
1465       
1466        if (programarguments.containsKey("debugSrcIsHome")) 
1467            setDebugSrcIsHome(true);
1468       
1469        // platform argument
1470        String platforms = programarguments.get("platform");
1471        if (platforms != null) {
1472            setTargetPlatforms(platforms.split(","));
1473        }
1474       
1475        // set options
1476        this.setOptions(programarguments);
1477       
1478        // Log compilation command
1479        log.info("Compiler arguments:\n  "        + programarguments.line());
1480        log.info("Current working directory:\n  " + currentWorkingDirecory());
1481        log.info("Compiler version: "             + COMPILER_VERSION);
1482        log.info("Java version: "                 + System.getProperty("java.version"));
1483        log.info("OS name: "                      + System.getProperty("os.name"));
1484        log.info("OS architecture: "              + System.getProperty("os.arch"));
1485        logEnvironment("MODELICAPATH", "JAVA_HOME", "JMODELICA_HOME");
1486    }
1487
1488    public static void main(String ... args) {
1489        // create an empty compiler
1490        ModelicaCompiler mc = new ModelicaCompiler();
1491        try {
1492            // set arguments
1493            Arguments arguments = new Arguments("ModelicaCompiler", args);
1494            mc.setArguments(arguments);
1495            // Compile model
1496            mc.compileModelFromCommandLine(args, arguments);
1497        } catch(Throwable e) {
1498            log.error(e);
1499            log.close();
1500            System.exit(1);
1501        }
1502    }
1503
1504    /**
1505     * Compile model given on command line options and print any error messages.
1506     */
1507    protected void compileModelFromCommandLine(String[] args, Arguments programarguments) {
1508        // Get files and class
1509        // TODO: move this into arguments class
1510        String[] files = splitFiles(programarguments.libraryPath());
1511        String className = programarguments.className();
1512        String compileTo = programarguments.out();
1513       
1514        // Compile model
1515        try {
1516            String targetType = programarguments.get("target");
1517            if (targetType == null || targetType.equals("fmume")) {
1518                targetType = "me";
1519            } else if (targetType.equals("fmucs")) {
1520                targetType = "cs";
1521            }
1522           
1523            //Compile
1524            compileUnit(className, files, targetType, programarguments.get("version"), compileTo);
1525           
1526        } catch (CompilerException ce) {
1527            if (options.getBooleanOption("generate_html_diagnostics") && getDiagnosticsGenerator() != null) 
1528                getDiagnosticsGenerator().writeProblems(ce.getProblems());
1529            log.logCompilerException(ce);
1530            closeLogger();
1531            System.exit(1);
1532        } catch (Throwable e) {
1533            log.error(e);
1534            closeLogger();
1535            System.exit(1);
1536        } finally {
1537            closeLogger();
1538        }
1539    }
1540
1541    /**
1542     * Split the argument containing the list of files into an array of filenames.
1543     */
1544    protected String[] splitFiles(String arg) {
1545        ArrayList<String> res = new ArrayList<String>();
1546        for (String part : arg.split(","))
1547            if (!part.equals(""))
1548                res.add(part);
1549        return res.toArray(new String[res.size()]);
1550    }
1551
1552    /**
1553     * Get the current working directory.
1554     */
1555    protected String currentWorkingDirecory() {
1556        try {
1557            return new File(".").getCanonicalPath();
1558        } catch (IOException e) {
1559            return "< could not get current working directory >";
1560        }
1561    }
1562
1563    /**
1564     * Write environment variables to logger.
1565     */
1566    protected void logEnvironment(String... names) {
1567        for (String name : names) {
1568            String val = System.getenv(name);
1569            log.info("%-15s = %s", name, (val == null) ? "" : val);
1570        }
1571    }
1572
1573    public enum TargetType {
1574        FMUME10, FMUME20, FMUCS10, FMUCS20, FMUMECS20, FMUX, CEVAL, NULL
1575    }
1576   
1577    /**
1578    * Target object, contains all information related to which target is compiled.
1579    *
1580    * The target is an enum that represents all different targets, the templates are in a separate class.
1581    */
1582    public enum TargetObject implements CCompilerTarget {
1583       
1584        FMUME10   (TargetType.FMUME10,   "fmume10",   "fmu",  XMLGeneratorHolder.FMI1),
1585        FMUME20   (TargetType.FMUME20,   "fmume20",   "fmu",  XMLGeneratorHolder.FMI2),
1586        FMUCS10   (TargetType.FMUCS10,   "fmucs10",   "fmu",  XMLGeneratorHolder.FMI1),
1587        FMUCS20   (TargetType.FMUCS20,   "fmucs20",   "fmu",  XMLGeneratorHolder.FMI2),
1588        FMUMECS20 (TargetType.FMUMECS20, "fmumecs20", "fmu",  XMLGeneratorHolder.FMI2), 
1589        FMUX      (TargetType.FMUX,      null,        "fmux", XMLGeneratorHolder.FMIX),
1590        CHECK     (TargetType.NULL,      null,        null,   XMLGeneratorHolder.NULL, ErrorCheckType.CHECK, false),
1591        PARSE     (TargetType.NULL,      null,        null,   XMLGeneratorHolder.NULL, ErrorCheckType.CHECK, false),
1592        NOCODEGEN (TargetType.NULL,      null,        null,   XMLGeneratorHolder.NULL, ErrorCheckType.COMPILE, false),
1593        CEVAL     (TargetType.CEVAL,     "ceval",     null  , null);
1594
1595        private final TargetType type;
1596        private final String makeFileFlag;
1597        private final String suffix;
1598        private final XMLGeneratorHolder xmlGenerator;
1599        private final ErrorCheckType checkType;
1600        private final boolean codeGen;
1601
1602        private TargetObject(TargetType type, String makeFileFlag, String suffix, XMLGeneratorHolder xmlGenerator, ErrorCheckType checkType, boolean codeGen) {
1603            this.type = type;
1604            this.makeFileFlag = makeFileFlag;
1605            this.suffix = suffix;
1606            this.checkType = checkType;
1607            this.codeGen = codeGen;
1608            this.xmlGenerator = xmlGenerator;
1609        }
1610
1611        private TargetObject(TargetType type, String makeFileFlag, String suffix, XMLGeneratorHolder xmlGenerator, ErrorCheckType checkType) {
1612            this(type, makeFileFlag, suffix, xmlGenerator, checkType, true);
1613        }
1614       
1615        private TargetObject(TargetType type, String makeFileFlag, String suffix, XMLGeneratorHolder xmlGenerator) {
1616            this(type, makeFileFlag, suffix, xmlGenerator, ErrorCheckType.COMPILE);
1617        }
1618       
1619        public Templates getTemplates(OptionRegistry options) {
1620            return new Templates(type, options);
1621        }
1622       
1623        public String createExtraCFlagsString(AbstractOptionRegistry abstractOptions, String fileName) {
1624            OptionRegistry options = (OptionRegistry) abstractOptions;
1625           
1626            if (suffix == null) {
1627                return "";
1628            }
1629           
1630            return getTemplates(options).createExtraCFlagsString(options, fileName);
1631        }
1632       
1633        /**
1634        * Returns an enum of the target that contains all relevant information for the target.
1635        *
1636        * @param targetType  The compiler target.
1637        * @param version     The FMI version.
1638        */
1639        public static TargetObject getTarget(String targetType, String version)
1640                throws IllegalCompilerArgumentException {
1641           
1642            if (targetType.equals("nocodegen")) {
1643                return NOCODEGEN;
1644            } else if (targetType.equals("me")) {
1645                if (version == null || version.equals("1.0")) {
1646                    return FMUME10;
1647                } else if (version.equals("2.0")) {
1648                    return FMUME20;
1649                } else {
1650                    throw new IllegalCompilerArgumentException("Unknown version '" + version + "' for target '" + targetType + "'. Use 1.0 or 2.0."); 
1651                }
1652            } else if (targetType.equals("cs")) {
1653                if (version == null || version.equals("1.0")) {
1654                    return FMUCS10;
1655                } else if (version.equals("2.0")) {
1656                    return FMUCS20;
1657                } else {
1658                    throw new IllegalCompilerArgumentException("Unknown version '" + version + "' for target '" + targetType + "'. Use 1.0 or 2.0."); 
1659                }
1660            } else if (targetType.equals("me+cs")) {
1661                if (version == null || version.equals("2.0")) {
1662                    return FMUMECS20;
1663                } else {
1664                    throw new IllegalCompilerArgumentException("Unknown version '" + version + "' for target '" + targetType + "'. Use 2.0.");
1665                }
1666            } else if (targetType.equals("fmux")) {
1667                return FMUX;
1668            } else if (targetType.equals("ceval")){
1669                return CEVAL;
1670            } else if (targetType.equals("parse")) {
1671                return PARSE;
1672            } else if (targetType.equals("check")) {
1673                return CHECK;
1674            } else {
1675                throw new IllegalCompilerArgumentException("Unknown target '" + targetType + "'. Use me or cs to compile an FMU or fmux to compile an FMUX."); 
1676            }
1677        }
1678       
1679        /**
1680         * Create a new XMLGenerator object.
1681         *
1682         * Override for subclasses needing another subclass of XMLGenerator.
1683         */
1684        public GenericXMLGenerator getXMLGenerator(FClass fc) {
1685            return xmlGenerator.getXMLGenerator(fc);
1686        }
1687       
1688        /**
1689         * get the flag should be used in the Makefile.
1690         *
1691         * @return The flag for the Makefile.
1692         *
1693         */
1694        public String getMakeFileFlag() {
1695            return makeFileFlag;
1696        }
1697       
1698        /**
1699         * Gets the file suffix for a the target object.
1700         */
1701        public String getUnitSuffix() {
1702            return suffix;
1703        }
1704       
1705        /**
1706         * Get the check type to use when error checking.
1707         */
1708        public ErrorCheckType getCheckType() {
1709            return checkType;
1710        }
1711       
1712        /**
1713         * Get a flag that determines if there should be any code-generation.
1714         */
1715        public boolean getCodeGenFlag() {
1716            return codeGen;
1717        }
1718
1719        /**
1720         * Sets the default options that should be used for this target object.
1721         */
1722        public void setDefaultOptions(AbstractOptionRegistry options) {
1723            for (TargetOptionContributor contributor :
1724                    TargetOptionContributor.TARGET_DEFAULT_OPTION_CONTRIBUTORS.values()) {
1725
1726                contributor.setOptions(this, options);
1727            }
1728        }
1729
1730    }
1731
1732    public static TargetOptionContributor addTargetOptionContributor(TargetOptionContributor contributor) {
1733        Map<String, TargetOptionContributor> contributors = TargetOptionContributor.TARGET_DEFAULT_OPTION_CONTRIBUTORS;
1734        String identity = contributor.identity();
1735
1736        if (contributors.containsKey(identity)) {
1737            return contributors.get(identity);
1738        }
1739
1740        contributors.put(identity, contributor);
1741        return contributor;
1742    }
1743
1744    private static final TargetOptionContributor TARGET_DEFAULT_BASE_CONTRIBUTOR = addTargetOptionContributor(
1745                    new ModelicaCompiler.TargetOptionContributor() {
1746
1747                        @Override
1748                        public void setOptions(TargetObject object, AbstractOptionRegistry options) {
1749                            switch (object) {
1750                                case FMUME10:
1751                                    options.setStringOption("fmu_type", "FMUME10");
1752                                    options.setBooleanOption("generate_ode", true);
1753                                    options.setBooleanOption("generate_dae", false);
1754                                    options.setBooleanOption("equation_sorting", true);
1755                                    options.setBooleanOption("generate_fmi_me_xml", true);
1756                                    options.setBooleanOption("generate_fmi_cs_xml", false);
1757                                    options.setBooleanOption("generate_xml_equations", false);
1758                                    break;
1759                                case FMUME20:
1760                                    options.setStringOption("fmu_type", "FMUME20");
1761                                    options.setBooleanOption("generate_ode", true);
1762                                    options.setBooleanOption("generate_dae", false);
1763                                    options.setBooleanOption("equation_sorting", true);
1764                                    options.setBooleanOption("generate_fmi_me_xml", true);
1765                                    options.setBooleanOption("generate_fmi_cs_xml", false);
1766                                    options.setBooleanOption("generate_xml_equations", false);
1767                                    break;
1768                                case CHECK:
1769                                    options.setBooleanOption("generate_ode", true);
1770                                    options.setBooleanOption("generate_dae", false);
1771                                    options.setBooleanOption("equation_sorting", true);
1772                                    options.setBooleanOption("generate_fmi_me_xml", true);
1773                                    options.setBooleanOption("generate_fmi_cs_xml", false);
1774                                    options.setBooleanOption("generate_xml_equations", false);
1775                                    break;
1776                                case FMUCS10:
1777                                    options.setStringOption("fmu_type", "FMUCS10");
1778                                    options.setBooleanOption("generate_ode", true);
1779                                    options.setBooleanOption("generate_dae", false);
1780                                    options.setBooleanOption("equation_sorting", true);
1781                                    options.setBooleanOption("generate_fmi_me_xml", false);
1782                                    options.setBooleanOption("generate_fmi_cs_xml", true);
1783                                    options.setBooleanOption("generate_xml_equations", false);
1784                                    break;
1785                                case FMUCS20:
1786                                    options.setStringOption("fmu_type", "FMUCS20");
1787                                    options.setBooleanOption("generate_ode", true);
1788                                    options.setBooleanOption("generate_dae", false);
1789                                    options.setBooleanOption("equation_sorting", true);
1790                                    options.setBooleanOption("generate_fmi_me_xml", false);
1791                                    options.setBooleanOption("generate_fmi_cs_xml", true);
1792                                    options.setBooleanOption("generate_xml_equations", false);
1793                                    break;
1794                                case FMUMECS20:
1795                                    options.setStringOption("fmu_type", "FMUME20;FMUCS20");
1796                                    options.setBooleanOption("generate_ode", true);
1797                                    options.setBooleanOption("generate_dae", false);
1798                                    options.setBooleanOption("equation_sorting", true);
1799                                    options.setBooleanOption("generate_fmi_me_xml", true);
1800                                    options.setBooleanOption("generate_fmi_cs_xml", true);
1801                                    options.setBooleanOption("generate_xml_equations", false);
1802                                    break;
1803                                case FMUX:
1804                                    options.setBooleanOption("generate_ode", false);
1805                                    options.setBooleanOption("generate_dae", true);
1806                                    options.setBooleanOption("equation_sorting", false);
1807                                    options.setBooleanOption("generate_fmi_me_xml", false);
1808                                    options.setBooleanOption("generate_fmi_cs_xml", false);
1809                                    options.setBooleanOption("generate_xml_equations", true);
1810                                    break;
1811                                case NOCODEGEN:
1812                                    options.setBooleanOption("unroll_functions", true);
1813                                    break;
1814                                default:
1815                                    break;
1816                                }
1817                            options.setStringOption("compiler_version", ModelicaCompiler.COMPILER_VERSION);
1818                        }
1819
1820                        @Override
1821                        public String identity() {
1822                            return "org.jmodelica.modelica.compiler.ModelicaCompiler.TARGET_DEFAULT_BASE_CONTRIBUTOR";
1823                        }
1824                    });
1825
1826    private static final TargetOptionContributor TARGET_FMI_VERSION_CONTRIBUTOR = addTargetOptionContributor(
1827                    new ModelicaCompiler.TargetOptionContributor() {
1828
1829                        @Override
1830                        public void setOptions(TargetObject object, AbstractOptionRegistry options) {
1831                            switch (object) {
1832                                case FMUME10:
1833                                case FMUCS10:
1834                                    options.setStringOption("fmi_version", OptionRegistry.FMIVersion.FMI10);
1835                                    break;
1836                                case FMUME20:
1837                                case FMUCS20:
1838                                case FMUMECS20:
1839                                    options.setStringOption("fmi_version", OptionRegistry.FMIVersion.FMI20);
1840                                    break;
1841                                default:
1842                                    break;
1843                            }
1844                        }
1845
1846                        @Override
1847                        public String identity() {
1848                            return "org.jmodelica.modelica.compiler.ModelicaCompiler.TARGET_FMI_VERSION_CONTRIBUTOR";
1849                        }
1850                    });
1851
1852    /**
1853     * Contributor class for additional default options dependent on compilation target.
1854     */
1855    public static abstract class TargetOptionContributor implements Comparable<TargetOptionContributor> {
1856
1857        private static final Map<String, TargetOptionContributor> TARGET_DEFAULT_OPTION_CONTRIBUTORS =
1858            new HashMap<String, TargetOptionContributor>();
1859
1860        protected abstract String identity();
1861        protected abstract void setOptions(TargetObject object, AbstractOptionRegistry options);
1862
1863        @Override
1864        public int compareTo(TargetOptionContributor other) {
1865            return identity().compareTo(other.identity());
1866        }
1867
1868        @Override
1869        public boolean equals(Object other) {
1870            if (!(other instanceof TargetOptionContributor)) {
1871                return false;
1872            }
1873            return compareTo((TargetOptionContributor) other) == 0;
1874        }
1875
1876    }
1877
1878}
1879
1880    /**
1881     * Retrieves the target platforms.
1882     *
1883     * @return  the target platforms.
1884     */
1885    public String[] ModelicaCompiler.getTargetPlatforms() {
1886        return targetPlatforms;
1887    }
1888
1889    /**
1890     * Sets the target platforms.
1891     *
1892     * @param platforms the platforms to set as compilation targets.
1893     */
1894    public void ModelicaCompiler.setTargetPlatforms(String... platforms) {
1895        this.targetPlatforms = platforms;
1896    }
1897
1898    /**
1899     * Sets the directory new temporary files are created in.
1900     * The default value is <code>null</code>, and is interpreted as the current working directory.
1901     */
1902    public void ModelicaCompiler.setTempFileDir(File temp) {
1903        tempDir = temp;
1904    }
1905
1906    public void ModelicaCompiler.setOutDir(File out) {
1907        outDir = out;
1908        sourceDir = new File(outDir, "sources");
1909        resourceDir = new File(outDir, "resources");
1910        sourceDir.mkdirs();
1911        resourceDir.mkdir();
1912    }
1913
1914    public void ModelicaCompiler.setSubOutDir(String out) {
1915        setOutDir(new File(tempDir, out));
1916    }
1917
1918    public void ModelicaCompiler.setRandomOutDir() {
1919        try {
1920            File out = File.createTempFile("jmc", "out", tempDir);
1921            out.delete();
1922            setOutDir(out);
1923        } catch (IOException e) {
1924            throw new ModelicaException("Unable to create temporary directory with prefix 'jmc', suffix 'out' and " +
1925                    "temp base directory '" + tempDir + "'! java.io.tmpdir: '" + System.getProperty("java.io.tmpdir") + 
1926                    "'. TMP: '" + System.getenv("TMP") + "'. TEMP: '" + System.getenv("TEMP") + "'.", e);
1927        }
1928    }
1929
1930    /**
1931     * Deletes the temporary out directory.
1932     */
1933    private void ModelicaCompiler.deleteOutDir() {
1934        if (outDir != null) {
1935            FileUtil.recursiveDelete(outDir);
1936        }
1937        outDir = null;
1938        sourceDir = null;
1939        resourceDir = null;
1940    }
1941
1942    /**
1943     * Compiles a Modelica model. A model file name and class must be provided.
1944     * Prints an error and returns without completion if, for example, a file
1945     * can not be found or if the parsing fails. Supports multiple model files.
1946     *
1947     * @param files
1948     *            Array of model file or library paths.
1949     * @param cl
1950     *            The name of the class in the model file to compile.
1951     * @param target
1952     *            The target object for the compiler.
1953     *
1954     * @return A flat representation of the class specified by <code>cl</code>.
1955     *            Returns null for some targets.
1956     *
1957     * @throws beaver.Parser.Exception
1958     *             If there was an Beaver parsing exception.
1959     * @throws CompilerException
1960     *             If errors have been found during the parsing, instantiation
1961     *             or flattening.
1962     * @throws FileNotFoundException
1963     *             If the model file can not be found.
1964     * @throws IOException
1965     *             If there was an error reading the model file. (Beaver
1966     *             exception.)
1967     * @throws IOException
1968     *             If there was an error creating the .mof file.
1969     * @throws ModelicaClassNotFoundException
1970     *             If the Modelica class to parse, instantiate or flatten is not
1971     *             found.
1972     * @deprecated Use {@link #compileModel(Path[], String, TargetObject, String, Path)} instead
1973     */
1974    public FClass ModelicaCompiler.compileModel(String files[], String cl, TargetObject target, String compileTo)
1975          throws ModelicaException, FileNotFoundException, IOException, beaver.Parser.Exception {
1976        return compileModel(stringsToPaths(files), cl, target, compileTo == null ? null : Paths.get(compileTo));
1977    }
1978   
1979    /**
1980     * Compiles a Modelica model. A model file name and class must be provided.
1981     * Prints an error and returns without completion if, for example, a file
1982     * can not be found or if the parsing fails. Supports multiple model files.
1983     *
1984     * @param files
1985     *            Array of model file or library paths.
1986     * @param cl
1987     *            The name of the class in the model file to compile.
1988     * @param target
1989     *            The target object for the compiler.
1990     *
1991     * @return A flat representation of the class specified by <code>cl</code>.
1992     *            Returns null for some targets.
1993     *
1994     * @throws beaver.Parser.Exception
1995     *             If there was an Beaver parsing exception.
1996     * @throws CompilerException
1997     *             If errors have been found during the parsing, instantiation
1998     *             or flattening.
1999     * @throws FileNotFoundException
2000     *             If the model file can not be found.
2001     * @throws IOException
2002     *             If there was an error reading the model file. (Beaver
2003     *             exception.)
2004     * @throws IOException
2005     *             If there was an error creating the .mof file.
2006     * @throws ModelicaClassNotFoundException
2007     *             If the Modelica class to parse, instantiate or flatten is not
2008     *             found.
2009     * @deprecated Use {@link #compileModel(Path[], String, TargetObject, String, Path)} instead
2010     */
2011     public FClass ModelicaCompiler.compileModel(Path files[], String cl, TargetObject target, Path compileTo)
2012          throws ModelicaException, FileNotFoundException, IOException, beaver.Parser.Exception {
2013        boolean doTearDown = true;
2014        try {
2015            doTearDown = trySetUp();
2016            return doCompileModel(files, cl, target, compileTo);
2017        } finally {
2018            tryTearDown(doTearDown);
2019        }
2020    }
2021   
2022   
2023    public FClass ModelicaCompiler.doCompileModel(Path name[], String cl, TargetObject target, Path compileTo)
2024          throws ModelicaException, FileNotFoundException, IOException, beaver.Parser.Exception {
2025        if (target.equals(TargetObject.PARSE)) {
2026            parseFiles(name);
2027            return null;
2028        } else if (target.equals(TargetObject.CHECK)) {
2029            try {
2030                instantiateModel(name, cl, target);
2031            } finally {
2032                if (outDir != null) {
2033                    deleteOutDir();
2034                }
2035            }
2036            return null;
2037        }
2038       
2039        log.info("======= Compiling model =======");
2040        resetCompilationInfo();
2041       
2042        FClass fc = null;
2043        try {
2044            // compute instance tree
2045            InstClassDecl icl = instantiateModel(name, cl, target);
2046            UtilInterface util = icl.root().getUtilInterface();
2047            String flatName = null;
2048            if (compileTo != null) {
2049                Path unitFile = makePackagingDirs(cl, compileTo, target);
2050                util.setCompilationOutputPath(unitFile);
2051                flatName = computeFlatName(compileTo, util);
2052            }
2053           
2054            // flattening
2055            // Throw away source and instance trees when they are not needed any more
2056            PassAndForget<InstClassDecl> buf = new PassAndForget<InstClassDecl>(icl);
2057            icl = null;
2058            fc = flattenModel(buf.pass(), target, flatName);
2059           
2060            // Generate code
2061            if (target.getCodeGenFlag()) {
2062                generateCode(fc, target);
2063                dumpMemoryUseFile(fc, util, "generated", false);
2064            }
2065           
2066            fc.loadResources(new File(outDir, "resources"));
2067           
2068        } finally {
2069        }
2070       
2071        if (options.getBooleanOption("generate_html_diagnostics"))
2072            setDiagnosticsGenerator(null);
2073       
2074        log.info("====== Model compiled successfully =======");
2075       
2076        return fc;
2077    }
2078   
2079    /**
2080     * If true, the compiler has been set up.
2081     */
2082    protected boolean ModelicaCompiler.isSetUp = false;
2083   
2084    /**
2085     * If the compiler has not been set up yet, do so and return true. If it
2086     * has been return false. It is the callers responsibility to call
2087     * {@link #tryTearDown(boolean)}.
2088     */
2089    protected boolean ModelicaCompiler.trySetUp() {
2090        return trySetUp(null);
2091    }
2092   
2093    /**
2094     *@see #trySetUp()
2095     */
2096    protected boolean ModelicaCompiler.trySetUp(IErrorHandler eh) {
2097        if (!isSetUp) {
2098            setUp(eh);
2099            return true;
2100        }
2101        return false;
2102    }
2103   
2104    /**
2105     * Set up the compiler. It is the callers responsibility to call
2106     * {@link #tearDown()}.
2107     *
2108     *@param IErrorHandler The error handler to use when compiling. If null the
2109     *                     default will be used.
2110     */
2111    public void ModelicaCompiler.setUp() {
2112        setUp(null);
2113    }
2114    protected void ModelicaCompiler.setUp(IErrorHandler eh) {
2115        if (isSetUp) {
2116            throw new InternalCompilerError("Compiler setup can only be performed once");
2117        }
2118        if (eh == null) {
2119            eh = new DefaultErrorHandler(options.getBooleanOption("halt_on_warning"));
2120            if (options.getBooleanOption("compliance_as_warning")) {
2121                eh = new ComplianceWarnErrorHandler(eh);
2122            }
2123        }
2124        setErrorHandler(eh);
2125        isSetUp = true;
2126    }
2127   
2128    public void ModelicaCompiler.checkSetUp() {
2129        if (!isSetUp) {
2130            throw new InternalCompilerError("Compiler setup not performed. Use ModelicaCompiler.setUp()");
2131        }
2132    }
2133   
2134    /**
2135     *@param doTearDown If true, run tear down.
2136     */
2137    protected void ModelicaCompiler.tryTearDown(boolean doTearDown) {
2138        if (doTearDown) {
2139            tearDown();
2140        }
2141    }
2142   
2143    /**
2144     * Tear down the compiler. Undo the work done in {@link #setUp(IErrorHandler)}.
2145     */
2146    public void ModelicaCompiler.tearDown() {
2147        createUtilInterface().tearDown();
2148        setErrorHandler(null);
2149        isSetUp = false;
2150    }
2151   
2152    protected void ModelicaCompiler.warning(String message) {
2153        errorHandler.problem(Problem.createProblem(null, ProblemSeverity.WARNING, ProblemKind.OTHER, message));
2154    }
2155   
2156    protected void ModelicaCompiler.error(String message) {
2157        errorHandler.problem(Problem.createProblem(null, ProblemSeverity.ERROR, ProblemKind.OTHER, message));
2158    }
2159
2160    /**
2161     * Generate an output file.
2162     *
2163     * @param fc    the FClass to generate code for
2164     * @param tmpl  the path to the template
2165     * @param gen   the code generator to use
2166     * @param dir   the directory to put the output file in
2167     * @param name  the name of the output file
2168     */
2169    SplitFilesCodeStream ModelicaCompiler.generateFile(FClass fc, String tmpl, AbstractGenerator gen, File dir, String name, String header) 
2170            throws FileNotFoundException {
2171
2172        if (tmpl != null || gen instanceof GenericXMLGenerator) {
2173            hookCheckAbort();
2174            hookCodeGeneratorCreated(gen);
2175            File outFile = new File(dir, name);
2176            boolean debugGen = options.getBooleanOption("debug_duplicate_generated");
2177            SplitFilesCodeStream stream = new SplitFilesCodeStream(outFile, debugGen, header);
2178            gen.generate(tmpl, stream, header);
2179            for (File file : stream.files()) {
2180                log.debug("Generated file '" + file + "'.");
2181                if (fc != null) {
2182                    fc.guidManager().addDependentFile(file);
2183                }
2184            }
2185            return stream;
2186        }
2187        return null;
2188    }
2189
2190    /**
2191     * Packs an FMU (helper function for {@link #compileUnit()}).
2192     */
2193    protected Path ModelicaCompiler.packUnit(String className,
2194            TargetObject target, FClass fClass) throws PackingFailedException {
2195        Path unitFile = fClass.root().getUtilInterface().getCompilationOutputPath();
2196       
2197        hookPackFmu(fClass, outDir);
2198        hookCheckAbort();
2199        packUnit(className, target, fClass, unitFile);
2200        hookFmuPacked(fClass, unitFile.toAbsolutePath().toFile());
2201       
2202        return unitFile;
2203    }
2204   
2205    private void ModelicaCompiler.packUnit(String className, TargetObject target, FClass fClass, Path unitFile) {
2206        try {
2207            copySourceFiles(fClass, sourceDir, outDir);
2208            try (ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(Files.newOutputStream(unitFile)))) {
2209                out.setMethod(ZipOutputStream.DEFLATED);
2210                zipDir(outDir, out);
2211            }
2212        } catch (Exception e) {
2213            throw new PackingFailedException(String.format("Could not write to '%s'.", unitFile), e);
2214        }
2215    }
2216
2217    /**
2218     * Copies source files.
2219     *
2220     * @param fClass        the flat tree for which the source code was compiled.
2221     * @param rootDir       the root directory that contains the sources.
2222     * @param destination   the destination to which to copy the source files.
2223     * @throws IOException  if there was any error copying or reading files.
2224     */
2225    private void ModelicaCompiler.copySourceFiles(FClass fClass, File rootDir, File destination) {
2226        if(!options.getBooleanOption("copy_source_files_to_fmu")) {
2227            FileUtil.recursiveDelete(sourceDir);
2228            sourceDir = null;
2229        }
2230    }
2231
2232    private void ModelicaCompiler.doCompileCCode(TargetObject target,  FClass fc) {
2233        if (target.getMakeFileFlag() != null) {
2234                ASTNode.beginStep("compileCCode()");
2235                String cFileName = fc.nameUnderscore();
2236                CCompilerDelegator ccompiler = getCCompiler();
2237                CCompilerArguments ccArgs = new CCompilerArguments(cFileName, fc.myOptions(), target, fc.externalLibraries(), fc.externalLibraryDirectories(), 
2238                        fc.externalIncludeDirectories());
2239                ccompiler.compileCCode(ModelicaCompiler.log, ccArgs, outDir);
2240                ccompiler.copySharedLibs(outDir, ccArgs.getExternalLibraries());
2241                ASTNode.endStep("compileCCode()");
2242        }
2243        hookCodeCompiled();
2244     }
2245
2246    /**
2247     * Calculates the destination directory for a packaged unit. If the specified destination is a file its directory
2248     * is chosen as destination. If the destination does not exist, it is created (using {@link Filed#createDirectories()}).
2249     *
2250     * @param className
2251     *          The qualified name of the class for to create a unit for.
2252     * @param destination
2253     *          The path where to put the packaged unit.
2254     * @param target
2255     *          A {@link TargetObject} containing information about the target.
2256     * @return
2257     *          the path to the destination file of the packaged unit.
2258     */ 
2259    private Path ModelicaCompiler.makePackagingDirs(String className, Path destination, TargetObject target)
2260            throws IOException {
2261        Path dest = destination.toAbsolutePath();
2262        if (Files.isDirectory(dest)) { 
2263            String mangledName = FClass.convertClassNameToUnderscore(className);
2264            dest = dest.resolve(mangledName + "." + target.getUnitSuffix());
2265        } else {
2266            Path destDir = dest.getParent();
2267            if (destDir != null && !Files.isDirectory(destDir)) {
2268                Files.createDirectories(dest.getParent());
2269            }
2270        }
2271        return dest;
2272    }
2273   
2274    private void ModelicaCompiler.generateAllFiles(FClass fc, TargetObject target, Templates templates, String name)
2275            throws FileNotFoundException {
2276        templates.generateCFiles(this, fc, createCGenerator(fc), sourceDir, name);
2277        templates.generateXMLFiles(this, fc, target.getXMLGenerator(fc), outDir, "modelDescription");
2278    }
2279   
2280    private String ModelicaCompiler.computeFlatName(Path compileTo, UtilInterface util) {
2281        String flatName = null;
2282        if (!Files.isDirectory(compileTo)) {
2283            flatName = compileTo.getFileName().toString();
2284            int i = flatName.lastIndexOf('.');
2285            if (i > 0) {
2286                flatName = flatName.substring(0, i);
2287            }
2288        }
2289        return flatName;
2290    }
2291
2292}
2293
2294
2295aspect CompilationHelpers {
2296
2297
2298syn boolean SourceRoot.isFileInLibrary() = findOutermostLibraryDir() != null;
2299
2300syn lazy Path SourceRoot.findOutermostLibraryDir() {
2301    if (getProgram().getNumUnstructuredEntity() != 1) 
2302        return null;
2303    else
2304        return getProgram().getUnstructuredEntity(0).findOutermostLibraryDir();
2305}
2306
2307syn Path SrcStoredDefinition.findOutermostLibraryDir() {
2308    if (!hasSrcWithin() || !getSrcWithin().hasPackageName()) {
2309        return null;
2310    }
2311    Path me = Paths.get(fileName()).toAbsolutePath();
2312    if (SrcLibNode.isPackageFile(me)) {
2313        me = me.getParent();
2314    }
2315    Path lib = getSrcWithin().getPackageName().findOutermostLibraryDirForWithin(me);
2316    return (lib != null) ? lib : null;
2317}
2318
2319syn Path SrcAccess.findOutermostLibraryDirForWithin(Path f) = null;
2320eq SrcDot.findOutermostLibraryDirForWithin(Path f) {
2321    for (int i = getNumSrcNamedAccess() - 1; i >= 0 && f != null; i--)
2322        f = getSrcNamedAccess(i).findOutermostLibraryDirForWithin(f);
2323    return f;
2324}
2325eq SrcNamedAccess.findOutermostLibraryDirForWithin(Path f) {
2326    f = f.getParent();
2327    if (f != null && f.getFileName().toString().equals(getID()) && SrcLibNode.isStructuredLib(f))
2328        return f;
2329    else 
2330        return null;
2331}
2332
2333
2334/**
2335 * Class for all templates.
2336 *
2337 * Support class for the target enum. Contains all templates, when creating
2338 * an instance templates are specified with a number.
2339 */
2340
2341public class Templates {
2342   
2343    private static final int XML = 0;
2344    private static final int C   = 1;
2345   
2346    private ModelicaCompiler.TargetType type;
2347   
2348    private String[] templates;
2349    private String templatePathPrefix;
2350    private boolean fmuTemplate;
2351   
2352    protected static final String[] DEBUG_TEMPLATE_IN_SRC = new String[] {
2353        "Compiler/ModelicaCBackEnd/templates",
2354        "Compiler/ModelicaFMUXBackEnd/templates",
2355        "Compiler/OptimicaFMUXBackEnd/templates",
2356    };
2357
2358
2359    public Templates(ModelicaCompiler.TargetType type, OptionRegistry options) {
2360        switch (type) {
2361        case FMUME10:
2362            templates = new String[] { null, "fmi1_me_modelica_template.c" };
2363            fmuTemplate = true;
2364            break;
2365        case FMUCS10:
2366            templates = new String[] { null, "fmi1_cs_modelica_template.c" };
2367            fmuTemplate = true;
2368            break;
2369        case FMUME20:
2370        case FMUCS20:
2371        case FMUMECS20:
2372            templates = new String[] { null, "fmi2_master_modelica_template.c" };
2373            fmuTemplate = true;
2374            break;
2375        case FMUX:
2376            templates = new String[] { "jmodelica_model_description.tpl" };
2377            break;
2378        case CEVAL:
2379            templates = new String[] { null, "ceval_external_template.c" };
2380            break;
2381        case NULL:
2382            templates = null;
2383            break;
2384        }
2385       
2386        this.type = type;
2387       
2388        if (CONTRIBUTORS != null) {
2389            for (TemplateContributor contributor : CONTRIBUTORS) {
2390                contributor.addTemplates(this, options);
2391            }
2392        }
2393    }
2394
2395    private String template(int i) {
2396        return (i < templates.length) ? templates[i] : null;
2397    }
2398   
2399    private String templatePath(String fileName, boolean debugSrcIsHome) {
2400        if (fileName == null) {
2401            return null;
2402        }
2403       
2404        File home = EnvironmentUtils.getJModelicaHome();
2405        if (debugSrcIsHome) {
2406            for (String dir : DEBUG_TEMPLATE_IN_SRC) {
2407                File f = new File(new File(home, dir), fileName);
2408                if (f.exists())
2409                    return f.getAbsolutePath();
2410            }
2411        } 
2412        return new File(templateDir(), fileName).getAbsolutePath();
2413    }
2414   
2415    private File templateDir() {
2416        return new File(EnvironmentUtils.getJModelicaHome(), "CodeGenTemplates");
2417    }
2418   
2419    public void generateXMLFiles(ModelicaCompiler mc, FClass fc, AbstractGenerator gen, File sourceDir, String name)
2420            throws FileNotFoundException {
2421        mc.generateFile(fc, templatePath(getXMLTemplateName(fc), mc.debugSrcIsHome), gen, sourceDir, name + ".xml", "");
2422    }
2423   
2424    public void generateCFiles(ModelicaCompiler mc, FClass fc, AbstractGenerator gen, File sourceDir, String name)
2425            throws FileNotFoundException {
2426        String header = "";
2427       
2428        if (fmuTemplate) {
2429            if (C_HEADER_TEMPLATES != null) {
2430                for (String tpl : C_HEADER_TEMPLATES) {
2431                    header = header + "#include \"" + name + "_" + tpl + ".h\"\n";
2432                }
2433            }
2434        }
2435       
2436        generateCFiles(mc, fc, gen, sourceDir, name, header);
2437       
2438        if (fmuTemplate) {
2439            if (C_HEADER_TEMPLATES != null) {
2440                for (String tpl : C_HEADER_TEMPLATES) {
2441                    String filename = tpl + ".h";
2442                    String path = new File("FMIBase", filename).toString();
2443                   
2444                    mc.generateFile(fc, templatePath(path, mc.debugSrcIsHome), gen, sourceDir, name + "_" + filename, "");
2445                }
2446            }
2447
2448            if (C_SOURCE_TEMPLATES != null) { 
2449                for (String tpl : C_SOURCE_TEMPLATES) {
2450                    String filename = tpl + ".c";
2451                    String path = new File("FMIBase", filename).toString();
2452                   
2453                    mc.generateFile(fc, templatePath(path, mc.debugSrcIsHome), gen, sourceDir, name + "_" + filename, header);
2454                }
2455            }
2456        }
2457    }
2458   
2459    public String createExtraCFlagsString(AbstractOptionRegistry options, String name) {
2460       
2461        if (C_SOURCE_TEMPLATES == null) {
2462            return "";
2463        }
2464       
2465        String applies_to = options.getStringOption("cc_extra_flags_applies_to");
2466        String flags = options.getStringOption("cc_extra_flags");
2467        StringBuilder sb = new StringBuilder();
2468        if (applies_to.equals(OptionRegistry.CCompilerFiles.ALL)) {
2469            sb.append("%");
2470            sb.append(flags);
2471        } else if (applies_to.equals(OptionRegistry.CCompilerFiles.FUNCTIONS)) {
2472            sb.append(name);
2473            sb.append("_");
2474            sb.append("funcs");
2475            sb.append(flags);
2476        }
2477        return sb.toString();
2478    }
2479   
2480    private void generateCFiles(ModelicaCompiler mc, FClass fc, AbstractGenerator gen, File sourceDir, String name, String header)
2481            throws FileNotFoundException {
2482        mc.generateFile(fc, templatePath(getCTemplateName(fc), mc.debugSrcIsHome), gen, sourceDir, name + ".c", header);
2483    }
2484   
2485    private static ArrayList<TemplateContributor> CONTRIBUTORS;
2486    private LinkedHashSet<String> XML_TEMPLATES;
2487    private LinkedHashSet<String> C_HEADER_TEMPLATES;
2488    private LinkedHashSet<String> C_SOURCE_TEMPLATES;   
2489   
2490    public abstract static class TemplateContributor {
2491        public void addTemplates(Templates templates, OptionRegistry options) { }
2492    }
2493
2494    public static <T extends TemplateContributor> T addContributor(T contributor) {
2495        if (CONTRIBUTORS == null) { CONTRIBUTORS = new ArrayList<TemplateContributor>(); }
2496       
2497        CONTRIBUTORS.add(contributor);
2498       
2499        return contributor;
2500    }
2501   
2502    public void addXMLTemplates(String ...template) {
2503        if (XML_TEMPLATES == null) { XML_TEMPLATES = new LinkedHashSet<String>(); }
2504       
2505        for (String tmpl : template) {
2506            XML_TEMPLATES.add(tmpl);
2507        }
2508    }
2509   
2510    public void addCSourceTemplates(String ...template) {
2511        if (C_SOURCE_TEMPLATES == null) { C_SOURCE_TEMPLATES = new LinkedHashSet<String>(); }
2512       
2513        for (String tmpl : template) {
2514            C_SOURCE_TEMPLATES.add(tmpl);
2515        }
2516    }
2517   
2518    public void addCHeaderTemplates(String ...template) {
2519        if (C_HEADER_TEMPLATES == null) { C_HEADER_TEMPLATES = new LinkedHashSet<String>(); }
2520       
2521        for (String tmpl : template) {
2522            C_HEADER_TEMPLATES.add(tmpl);
2523        }
2524    }
2525}
2526   
2527private String Templates.getCTemplateName(FClass fc) {
2528    return template(C);
2529}
2530
2531private String Templates.getXMLTemplateName(FClass fc) {
2532    return template(XML);
2533}
2534
2535private static final Templates.TemplateContributor ModelicaCompiler.BASIC_TEMPLATES =
2536    Templates.addContributor(new Templates.TemplateContributor() {
2537
2538        @Override
2539        public void addTemplates(Templates templates, OptionRegistry options) {
2540            templates.addCHeaderTemplates("base");
2541            templates.addCSourceTemplates("base", "init_independent", "init_dependent", "equ_init", "equ", "funcs");
2542        }
2543    });
2544
2545public class XMLGeneratorHolder {
2546
2547    public static final XMLGeneratorHolder NULL  = new XMLGeneratorHolder();
2548    public static final XMLGeneratorHolder FMI1  = new XMLGeneratorHolder(Fmi1XMLGenerator.CREATOR);
2549    public static final XMLGeneratorHolder FMI2  = new XMLGeneratorHolder(Fmi2XMLGenerator.CREATOR);
2550    public static final XMLGeneratorHolder JMI   = new XMLGeneratorHolder(XMLGenerator.CREATOR);
2551    public static final XMLGeneratorHolder FMIX  = new XMLGeneratorHolder(XMLGenerator.CREATOR);
2552
2553    private final GenericXMLGenerator.Creator xmlGen;
2554
2555    private XMLGeneratorHolder(GenericXMLGenerator.Creator xmlGen) {
2556        this.xmlGen = xmlGen;
2557    }
2558
2559    private XMLGeneratorHolder() {
2560        this.xmlGen = null;
2561    }
2562}
2563
2564public GenericXMLGenerator XMLGeneratorHolder.getXMLGenerator(FClass fc) {
2565    if (xmlGen == null) {
2566        return null;
2567    }
2568   
2569    return (GenericXMLGenerator) xmlGen.create(ASTNode.prettyPrinter, '$', fc);
2570}
2571
2572public enum Module { GET_SET }
2573
2574public class ModulesSettings {
2575   
2576    public ModulesSettings(OptionRegistry options) {
2577        /* Add default modules */
2578        addLibrary(Module.GET_SET, "jmi_get_set_default");
2579       
2580        for (ModuleContributor contributor : CONTRIBUTORS) {
2581            contributor.addModule(this, options);
2582        }
2583    }
2584     
2585    public void addLibrary(Module module, String name) {
2586        libraryNames.put(module,  name);
2587    }
2588   
2589    public java.util.List<String> getLibraryNames() {
2590        return new ArrayList(libraryNames.values());
2591    }
2592   
2593    private static ArrayList<ModuleContributor> CONTRIBUTORS = new ArrayList<>();
2594    private HashMap<Module, String> libraryNames = new HashMap<>();
2595   
2596    public abstract static class ModuleContributor {
2597        public void addModule(ModulesSettings settings, OptionRegistry options) { }
2598    }
2599   
2600    public static <T extends ModuleContributor> T addContributor(T contributor) {
2601        CONTRIBUTORS.add(contributor);
2602       
2603        return contributor;
2604    }
2605}
2606
2607/**
2608 * Interface for hooking into the compilation process.
2609 *
2610 * Trees passed as arguments may be altered, but implementer must take care
2611 * not to break compilation in this way.
2612 */
2613public interface CompilationHooks {
2614    /**
2615     * Returns <code>true</code> if the compilation should be aborted.
2616     *
2617     * May be called at any time, and is guaranteed to be called before each
2618     * compilation step with a separate method in this interface.
2619     *
2620     * If compilation is aborted before it is finished, a
2621     * {@link CompilationAbortedException} is thrown.
2622     */
2623    boolean shouldAbort(ModelicaCompiler instance);
2624   
2625    /**
2626     * Called after the supplied code files are parsed.
2627     */
2628    void filesParsed(ModelicaCompiler instance, SourceRoot sr);
2629   
2630    /**
2631     * Called after the error checks on the instantiated model are finished without errors.
2632     *
2633     * Since the instance tree is built lazily, this step can not be broken up.
2634     */
2635    void modelInstantiated(ModelicaCompiler instance, InstClassDecl icd);
2636   
2637    /**
2638     * Called after the model is flattened.
2639     */
2640    void modelFlattened(ModelicaCompiler instance, FClass fc);
2641   
2642    /**
2643     * Called after transformations are applied to the flat model.
2644     */
2645    void modelTransformed(ModelicaCompiler instance, FClass fc);
2646   
2647    /**
2648     * Called after error checks of the flat model are finished without errors.
2649     */
2650    void flatModelChecked(ModelicaCompiler instance, FClass fc);
2651   
2652    /**
2653     * Called after a code generator is created.
2654     *
2655     * Normally called three times.
2656     */
2657    void codeGeneratorCreated(ModelicaCompiler instance, AbstractGenerator gen);
2658   
2659    /**
2660     * Called after output code is generated.
2661     */
2662    void codeGenerated(ModelicaCompiler instance, FClass fc, File dir);
2663   
2664    /**
2665     * Called after the generated C code is compiled.
2666     */
2667    void codeCompiled(ModelicaCompiler instance);
2668
2669    /**
2670     * Called before the FMU is packed.
2671     *
2672     * @param instance compiler instance calling this hook
2673     * @param fc the source FClass
2674     * @param dir the temporary directory containing files to be packed in the FMU
2675     */
2676    public void packFmu(ModelicaCompiler instance, FClass fc, File dir);
2677
2678    /**
2679     * Called after the FMU is packed.
2680     */
2681    void fmuPacked(ModelicaCompiler instance, FClass fc, File path);
2682}
2683
2684/**
2685 * Functional interface for callbacks that should run before compilation starts.
2686 */
2687public interface CompilationStartListener {
2688    /**
2689     * Called before compiling ({@link ModelicaCompiler#compileUnit()}).
2690     * @param mc the ModelicaCompiler instance that will start compiling.
2691     */
2692    void onCompileStart(ModelicaCompiler mc);
2693}
2694
2695public abstract class CompilationHooksImpl implements CompilationHooks {
2696    @Override
2697    public boolean shouldAbort(ModelicaCompiler instance) { return false; }
2698    @Override
2699    public void modelTransformed(ModelicaCompiler instance, FClass fc) {}
2700    @Override
2701    public void modelInstantiated(ModelicaCompiler instance, InstClassDecl icd) {}
2702    @Override
2703    public void modelFlattened(ModelicaCompiler instance, FClass fc) {}
2704    @Override
2705    public void packFmu(ModelicaCompiler instance, FClass fc, File dir) {}
2706    @Override
2707    public void fmuPacked(ModelicaCompiler instance, FClass fc, File path) {}
2708    @Override
2709    public void flatModelChecked(ModelicaCompiler instance, FClass fc) {}
2710    @Override
2711    public void filesParsed(ModelicaCompiler instance, SourceRoot sr) {}
2712    @Override
2713    public void codeGeneratorCreated(ModelicaCompiler instance, AbstractGenerator gen) {}
2714    @Override
2715    public void codeGenerated(ModelicaCompiler instance, FClass fc, File dir) {}
2716    @Override
2717    public void codeCompiled(ModelicaCompiler instance) {}
2718}
2719
2720/**
2721 * Thrown when a compilation is aborted through a CompilationHooks.
2722 */
2723public class CompilationAbortedException extends RuntimeException {
2724    public CompilationAbortedException() {
2725    }
2726    public CompilationAbortedException(String msg) {
2727        super(msg);
2728    }
2729}
2730
2731    public class ModelicaCompiler {
2732        static {
2733            // Ensures that we load the class when this class is loaded!
2734            GccCompilerDelegator.CREATOR.getClass();
2735        }
2736    }
2737}
2738
2739aspect Version {
2740    public class Version {
2741        public static String parseVersion() {
2742            String version   = "unknown";
2743            String jmhome = System.getenv("JMODELICA_HOME");
2744            if (jmhome != null) {
2745                File versionFile = new File(jmhome, "version.txt");
2746                try {
2747                    BufferedReader is = new BufferedReader(new InputStreamReader(new FileInputStream(versionFile)));
2748                    StringBuilder sb = new StringBuilder();
2749                    String line;
2750                    while ((line = is.readLine()) != null)
2751                        sb.append(line);
2752                    version = sb.toString();
2753                } catch (IOException e) {
2754                   
2755                }
2756            }
2757            return version;
2758        }
2759       
2760        public static void main(String ... args) {
2761            System.out.println(parseVersion());
2762        }
2763    }
2764}
Note: See TracBrowser for help on using the repository browser.