source: branches/dev-mj-1626/Compiler/ModelicaCompiler/src/jastadd/ModelicaCompiler.jrag @ 13095

Last change on this file since 13095 was 13095, checked in by tgutzmann, 5 months ago

Merge from trunk

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