source: trunk/Compiler/ModelicaCompiler/src/jastadd/ModelicaCompiler.jrag @ 13719

Last change on this file since 13719 was 13719, checked in by Christian Andersson, 8 weeks ago

Recommitted changeset:13700 to trunk with two bug fixes. Related to ticket:5837

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