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

Last change on this file since 13998 was 13998, checked in by jwedin, 4 weeks ago

Removed the unused interface NodeCountExtra. Updated the documentation for the node count functionality. #5865

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