You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openoffice.apache.org by da...@apache.org on 2020/02/02 00:30:28 UTC

[openoffice] 02/02: Add my gotoSCons parser/convert from gbuild to scons.

This is an automated email from the ASF dual-hosted git repository.

damjan pushed a commit to branch scons-build
in repository https://gitbox.apache.org/repos/asf/openoffice.git

commit 1c93647b34c19875eb2476af6414246521a29b4e
Author: Damjan Jovanovic <da...@apache.org>
AuthorDate: Sun Feb 2 02:29:33 2020 +0200

    Add my gotoSCons parser/convert from gbuild to scons.
    
    Patch by: me
---
 gotoSCons/.gitignore                               |   4 +
 gotoSCons/pom.xml                                  |  21 ++
 .../openoffice/gotoSCons/GBuildConverter.java      |  82 ++++++++
 .../apache/openoffice/gotoSCons/GBuildParser.java  | 108 ++++++++++
 .../openoffice/gotoSCons/SConsConverter.java       | 231 +++++++++++++++++++++
 .../org/apache/openoffice/gotoSCons/Utils.java     |  37 ++++
 .../openoffice/gotoSCons/raw/FunctionNode.java     |  43 ++++
 .../apache/openoffice/gotoSCons/raw/ListNode.java  |  43 ++++
 .../org/apache/openoffice/gotoSCons/raw/Node.java  |  30 +++
 .../apache/openoffice/gotoSCons/raw/ValueNode.java |  40 ++++
 .../opeonoffice/gotoSCons/targets/BaseBinary.java  | 211 +++++++++++++++++++
 .../opeonoffice/gotoSCons/targets/BaseTarget.java  |  59 ++++++
 .../opeonoffice/gotoSCons/targets/Executable.java  | 107 ++++++++++
 .../opeonoffice/gotoSCons/targets/Library.java     |  99 +++++++++
 .../opeonoffice/gotoSCons/targets/Module.java      | 138 ++++++++++++
 .../apache/opeonoffice/gotoSCons/targets/Pkg.java  | 101 +++++++++
 .../opeonoffice/gotoSCons/targets/Repository.java  | 134 ++++++++++++
 17 files changed, 1488 insertions(+)

diff --git a/gotoSCons/.gitignore b/gotoSCons/.gitignore
new file mode 100644
index 0000000..4c04fd5
--- /dev/null
+++ b/gotoSCons/.gitignore
@@ -0,0 +1,4 @@
+.classpath
+.project
+.settings
+target/
diff --git a/gotoSCons/pom.xml b/gotoSCons/pom.xml
new file mode 100644
index 0000000..8a758f0
--- /dev/null
+++ b/gotoSCons/pom.xml
@@ -0,0 +1,21 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>local</groupId>
+  <artifactId>gotoSCons</artifactId>
+  <version>0.1-SNAPSHOT</version>
+  
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>3.1</version>
+        <configuration>
+          <source>1.7</source>
+          <target>1.7</target>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+    <name>gotoSCons</name>
+</project>
\ No newline at end of file
diff --git a/gotoSCons/src/main/java/org/apache/openoffice/gotoSCons/GBuildConverter.java b/gotoSCons/src/main/java/org/apache/openoffice/gotoSCons/GBuildConverter.java
new file mode 100644
index 0000000..81cac93
--- /dev/null
+++ b/gotoSCons/src/main/java/org/apache/openoffice/gotoSCons/GBuildConverter.java
@@ -0,0 +1,82 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package org.apache.openoffice.gotoSCons;
+
+import java.io.File;
+import java.util.Set;
+import java.util.TreeSet;
+import org.apache.opeonoffice.gotoSCons.targets.Library;
+import org.apache.opeonoffice.gotoSCons.targets.Module;
+import org.apache.opeonoffice.gotoSCons.targets.Repository;
+
+public class GBuildConverter {
+    public static void main(String[] args) throws Exception {
+        if (args.length < 1) {
+            System.err.println("Needs args");
+            System.exit(1);
+        }
+        if (args[0].equals("parsingAnalysis")) {
+            parsingAnalysis(args);
+        } else if (args[0].equals("parseModule")) {
+            if (args.length < 2) {
+                throw new Exception("Needs path to Module_xxx.mk");
+            }
+            Module module = new Module(new File(args[1]));
+            Repository repo = new Repository(new File(
+                    module.getFilename().getParentFile().getParentFile(), "Repository.mk"));
+            new SConsConverter(repo, System.out).convertToSCons(module);
+        } else if (args[0].equals("parseLibrary")) {
+            if (args.length < 2) {
+                throw new Exception("Needs path to Library_xxx.mk");
+            }
+            Library library = new Library(new File(args[1]));
+            System.out.println(library);
+        } else {
+            throw new Exception("Unsupported args");
+        }
+    }
+
+    public static void parsingAnalysis(String[] args) throws Exception {
+        File dir = new File(args[1]);
+        int modules = 0;
+        int parsable = 0;
+        Set<String> parsed = new TreeSet<>();
+        for (File file : dir.listFiles()) {
+            if (file.isDirectory()) {
+                if (new File(new File(file, "prj"), "makefile.mk").exists()) {
+                    ++modules;
+                    try {
+                        Module module = new Module(new File(file, "Module_" + file.getName() + ".mk"));
+                        ++parsable;
+                        parsed.add(module.getName());
+                    } catch (Exception ex) {
+                        System.err.println("============");
+                        System.err.print(file.getName() + "#"); // for easy "module#message" separation into CSV
+                        ex.printStackTrace();
+                    }
+                }
+            }
+        }
+        System.out.println("Could parse: " + parsed.toString());
+        System.out.println("" + parsable + " out of " + modules + " gbuild modules are parseable");
+    }
+}
diff --git a/gotoSCons/src/main/java/org/apache/openoffice/gotoSCons/GBuildParser.java b/gotoSCons/src/main/java/org/apache/openoffice/gotoSCons/GBuildParser.java
new file mode 100644
index 0000000..d35ffe2
--- /dev/null
+++ b/gotoSCons/src/main/java/org/apache/openoffice/gotoSCons/GBuildParser.java
@@ -0,0 +1,108 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package org.apache.openoffice.gotoSCons;
+
+import java.io.BufferedReader;
+import java.util.ArrayList;
+
+import org.apache.openoffice.gotoSCons.raw.FunctionNode;
+import org.apache.openoffice.gotoSCons.raw.ListNode;
+import org.apache.openoffice.gotoSCons.raw.Node;
+import org.apache.openoffice.gotoSCons.raw.ValueNode;
+
+public class GBuildParser {
+    
+    public ListNode parse(BufferedReader reader) throws Exception {
+        String fullLine = "";
+        String line;
+        ArrayList<Node> nodes = new ArrayList<>();
+        while ((line = reader.readLine()) != null) {
+            if (line.endsWith("\\")) {
+                fullLine += line.substring(0, line.length() - 1);
+            } else {
+                Node node = parseLine(fullLine + line);
+                fullLine = "";
+                if (node != null) {
+                    nodes.add(node);
+                }
+            }
+        }
+        
+        ListNode listNode = new ListNode(nodes.toArray(new Node[0]));
+        return listNode;
+    }
+    
+    private Node parseLine(String line) throws Exception {
+        if (line.startsWith("#")) {
+            return null;
+        }
+        
+        if (line.isEmpty()) {
+            return null;
+        }
+        
+        //System.out.println(line);
+        return evaluateExpression(line);
+    }
+    
+    private Node evaluateExpression(String expr) throws Exception {
+        // $(gb_STDLIBS)
+        // $(call gb_Library_Library,fileacc)
+        // $(call gb_Library_set_include,fileacc,$$(INCLUDE) -I$(SRCDIR)/fileaccess/inc)
+        if (expr.startsWith("$(")) {
+            StringBuilder token = new StringBuilder();
+            int brackets = 1;
+            int i;
+            for (i = 2; i < expr.length(); i++) {
+                if (expr.charAt(i) == ')') {
+                    --brackets;
+                    if (brackets == 0) {
+                        break;
+                    }
+                } else if (expr.charAt(i) == '(') {
+                    brackets++;
+                }
+                token.append(expr.charAt(i));
+            }
+            if (i < (expr.length() - 1)) {
+                throw new Exception("Expression ends early; explicit dependencies are not supported! " +
+                        "Expression was: " + expr);
+            }
+            
+            int firstSpace = token.indexOf(" ");
+            if (firstSpace > 0) {
+                String function = token.substring(0, firstSpace);
+                Node args = evaluateExpression(token.substring(firstSpace + 1));
+                return new FunctionNode(function, args);
+            } else {
+                return new ValueNode(expr);
+            }
+        } else {
+            if (expr.contains(" : ")) {
+                throw new Exception("Explicit dependencies are not supported! " +
+                        "Expression was: " + expr);
+            }
+            return new ValueNode(expr);
+        }
+    }
+    
+}
diff --git a/gotoSCons/src/main/java/org/apache/openoffice/gotoSCons/SConsConverter.java b/gotoSCons/src/main/java/org/apache/openoffice/gotoSCons/SConsConverter.java
new file mode 100644
index 0000000..9bdcef7
--- /dev/null
+++ b/gotoSCons/src/main/java/org/apache/openoffice/gotoSCons/SConsConverter.java
@@ -0,0 +1,231 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package org.apache.openoffice.gotoSCons;
+
+import java.io.File;
+import java.io.PrintStream;
+import java.util.Map;
+import org.apache.opeonoffice.gotoSCons.targets.BaseBinary;
+import org.apache.opeonoffice.gotoSCons.targets.Executable;
+import org.apache.opeonoffice.gotoSCons.targets.Library;
+import org.apache.opeonoffice.gotoSCons.targets.Module;
+import org.apache.opeonoffice.gotoSCons.targets.Pkg;
+import org.apache.opeonoffice.gotoSCons.targets.Repository;
+
+public class SConsConverter {
+    private Repository repo;
+    private PrintStream out;
+    
+    public SConsConverter(Repository repo, PrintStream out) {
+        this.repo = repo;
+        this.out = out;
+    }
+    
+    public void convertToSCons(Module module) throws Exception {
+        for (Library library : module.getLibraries().values()) {
+            convertLibrary(library);
+        }
+        
+        for (Executable exe : module.getExecutables().values()) {
+            convertExecutable(exe);
+        }
+        
+        for (Pkg pkg : module.getPackages().values()) {
+            for (Map.Entry<String, String> entry : pkg.getFilesToFrom().entrySet()) {
+                String toPath = entry.getKey();
+                String fromPath = pkg.getBaseDir() + '/' + entry.getValue();
+                
+                File moduleDir = module.getFilename().getParentFile().getCanonicalFile();
+                String expandedFromPath = fromPath.replace("$(SRCDIR)", moduleDir.getParentFile().getCanonicalPath());
+                String moduleRelativeFromPath;
+                if (expandedFromPath.startsWith(moduleDir.getCanonicalPath())) {
+                    moduleRelativeFromPath = expandedFromPath.substring(moduleDir.getCanonicalPath().length() + 1);
+                } else {
+                    throw new Exception("Cannot find module relative path to " + fromPath);
+                }
+                
+                out.println(String.format("Install('${OUTDIR}/%s', '%s')", toPath, moduleRelativeFromPath));
+            }
+            out.println();
+        }
+    }
+    
+    private void convertLibrary(Library library) throws Exception {
+        String objectsVariable = convertObjects(library);
+
+        String layer = repo.getLibraryLayer(library.getName());
+        out.println(String.format("%s = AOOSharedLibrary(", library.getName()));
+        out.println(String.format("    '%s',", library.getName()));
+        out.println(String.format("    '%s',", layer));
+        out.println(String.format("    %s.objects", objectsVariable));
+        out.println(String.format(")"));
+
+        if (!library.getLinkedLibs().isEmpty()) {
+            out.println(String.format("%s.AddLinkedLibs([", library.getName()));
+            boolean first = true;
+            for (String linkedLib : library.getLinkedLibs()) {
+                if (!first) {
+                    out.println(",");
+                }
+                out.print("    '" + linkedLib + "'");
+                first = false;
+            }
+            out.println();
+            out.println("])");
+        }
+
+        String componentFile = library.getComponentFile();
+        if (componentFile != null) {
+            int firstSlash = componentFile.indexOf('/');
+            if (firstSlash < 0) {
+                throw new Exception("Invalid filename " + componentFile);
+            }
+
+            out.println(String.format("%s.SetComponentFile('%s')",
+                    library.getName(), componentFile.substring(firstSlash + 1)));
+        }
+
+        out.println(String.format("%s.InstallTo('${OUTDIR}/lib')", library.getName()));
+        out.println();
+    }
+    
+    private void convertExecutable(Executable exe) throws Exception {
+        String objectsVariable = convertObjects(exe);
+
+        String layer = repo.getExecutableLayer(exe.getName());
+        out.println(String.format("%s = AOOExecutable(", exe.getName()));
+        out.println(String.format("    '%s',", exe.getName()));
+        out.println(String.format("    '%s',", layer));
+        out.println(String.format("    %s.objects", objectsVariable));
+        out.println(String.format(")"));
+        
+        if (exe.isTargetTypeSet()) {
+            out.println(String.format("%s.SetTargetTypeGUI()",
+                    exe.getName(),
+                    exe.isIsTargetTypeGUI() ? "True" : "False"));
+        }
+
+        if (!exe.getLinkedLibs().isEmpty()) {
+            out.println(String.format("%s.AddLinkedLibs([", exe.getName()));
+            boolean first = true;
+            for (String linkedLib : exe.getLinkedLibs()) {
+                if (!first) {
+                    out.println(",");
+                }
+                out.print("    '" + linkedLib + "'");
+                first = false;
+            }
+            out.println();
+            out.println("])");
+        }
+
+        out.println(String.format("%s.InstallTo('${OUTDIR}/bin')", exe.getName()));
+        out.println();
+    }
+    
+    private String convertObjects(BaseBinary binary) throws Exception {
+        String objectsVariable = binary.getName() + "Objects";
+        if (binary.getExceptionObjects().isEmpty()) {
+            throw new Exception("How can a binary have no source files?");
+        }
+        out.println(objectsVariable + " = AOOSharedObjects()");
+        
+        if (!binary.getApis().isEmpty()) {
+            out.println(objectsVariable + ".AddAPI([");
+            boolean first = true;
+            for (String api : binary.getApis()) {
+                if (!first) {
+                    out.println(",");
+                }
+                out.print("    '" + api + "'");
+                first = false;
+            }
+            out.println();
+            out.println("])");
+        }
+            
+        if (!binary.getIncludes().isEmpty()) {
+            out.println(objectsVariable + ".AddInclude([");
+            boolean first = true;
+            for (String include : binary.getIncludes()) {
+                if (include.equals("$$(INCLUDE)")) {
+                    continue;
+                }
+                if (include.startsWith("-I")) {
+                    include = include.substring(2);
+                }
+                if (include.startsWith("$(SRCDIR)/")) {
+                    int firstSlash = include.indexOf('/');
+                    int secondSlash = include.indexOf('/', firstSlash + 1);
+                    include = include.substring(secondSlash + 1);
+                }
+
+                if (!first) {
+                    out.println(",");
+                }
+                out.print("    '" + include + "'");
+                first = false;
+            }
+            out.println();
+            out.println("])");
+        }
+
+        if (!binary.getDefs().isEmpty()) {
+            out.println(objectsVariable + ".AddDefs([");
+            boolean first = true;
+            for (String def : binary.getDefs()) {
+                if (!first) {
+                    out.println(",");
+                }
+                if (def.startsWith("-D")) {
+                    def = def.substring(2);
+                }
+                out.print("    '" + def + "'");
+                first = false;
+            }
+            out.println();
+            out.println("])");
+        }
+
+        if (!binary.getExceptionObjects().isEmpty()) {
+            out.println(objectsVariable + ".AddCxxExceptionSources([");
+            boolean first = true;
+            for (String exceptionObject : binary.getExceptionObjects()) {
+                if (!first) {
+                    out.println(",");
+                }
+                // in: fileaccess/source/FileAccess
+                // out: source/FileAccess.cxx
+                int firstSlash = exceptionObject.indexOf('/');
+                if (firstSlash < 0) {
+                    throw new Exception("Invalid filename " + exceptionObject);
+                }
+                out.print("    '" + exceptionObject.substring(firstSlash + 1) + ".cxx'");
+                first = false;
+            }
+            out.println();
+            out.println("])");
+        }
+        
+        return objectsVariable;
+    }
+}
diff --git a/gotoSCons/src/main/java/org/apache/openoffice/gotoSCons/Utils.java b/gotoSCons/src/main/java/org/apache/openoffice/gotoSCons/Utils.java
new file mode 100644
index 0000000..cfae779
--- /dev/null
+++ b/gotoSCons/src/main/java/org/apache/openoffice/gotoSCons/Utils.java
@@ -0,0 +1,37 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package org.apache.openoffice.gotoSCons;
+
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+
+public class Utils {
+    public static String[] spaceSeparatedTokens(String text) throws Exception {
+        StringTokenizer tokenizer = new StringTokenizer(text, " \t", false);
+        ArrayList<String> tokens = new ArrayList<>();
+        while (tokenizer.hasMoreElements()) {
+            tokens.add((String)tokenizer.nextElement());
+        }
+        return tokens.toArray(new String[0]);
+    }
+
+}
diff --git a/gotoSCons/src/main/java/org/apache/openoffice/gotoSCons/raw/FunctionNode.java b/gotoSCons/src/main/java/org/apache/openoffice/gotoSCons/raw/FunctionNode.java
new file mode 100644
index 0000000..792ea92
--- /dev/null
+++ b/gotoSCons/src/main/java/org/apache/openoffice/gotoSCons/raw/FunctionNode.java
@@ -0,0 +1,43 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package org.apache.openoffice.gotoSCons.raw;
+
+public class FunctionNode extends Node {
+    public String function;
+    public Node child;
+    
+    public FunctionNode(String function, Node child) {
+        this.function = function;
+        this.child = child;
+    }
+    
+    @Override
+    protected void dump(String space) {
+        System.out.println(space + "function " + function);
+        child.dump(space + "    ");
+    }
+
+    @Override
+    public String toString() {
+        return function + "(...)";
+    }
+}
diff --git a/gotoSCons/src/main/java/org/apache/openoffice/gotoSCons/raw/ListNode.java b/gotoSCons/src/main/java/org/apache/openoffice/gotoSCons/raw/ListNode.java
new file mode 100644
index 0000000..8a6c26b
--- /dev/null
+++ b/gotoSCons/src/main/java/org/apache/openoffice/gotoSCons/raw/ListNode.java
@@ -0,0 +1,43 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package org.apache.openoffice.gotoSCons.raw;
+
+public class ListNode extends Node {
+    public Node[] children;
+    
+    public ListNode(Node[] children) {
+        this.children = children;
+    }
+    
+    @Override
+    protected void dump(String space) {
+        System.out.println(space + "(list)");
+        for (Node child : children) {
+            child.dump(space + "    ");
+        }
+    }
+
+    @Override
+    public String toString() {
+        return children.toString();
+    }
+}
diff --git a/gotoSCons/src/main/java/org/apache/openoffice/gotoSCons/raw/Node.java b/gotoSCons/src/main/java/org/apache/openoffice/gotoSCons/raw/Node.java
new file mode 100644
index 0000000..d9b62d1
--- /dev/null
+++ b/gotoSCons/src/main/java/org/apache/openoffice/gotoSCons/raw/Node.java
@@ -0,0 +1,30 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package org.apache.openoffice.gotoSCons.raw;
+
+public abstract class Node {
+    public final void dump() {
+        dump("");
+    }
+    
+    protected abstract void dump(String space);
+}
diff --git a/gotoSCons/src/main/java/org/apache/openoffice/gotoSCons/raw/ValueNode.java b/gotoSCons/src/main/java/org/apache/openoffice/gotoSCons/raw/ValueNode.java
new file mode 100644
index 0000000..823208e
--- /dev/null
+++ b/gotoSCons/src/main/java/org/apache/openoffice/gotoSCons/raw/ValueNode.java
@@ -0,0 +1,40 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package org.apache.openoffice.gotoSCons.raw;
+
+public class ValueNode extends Node {
+    public String value;
+    
+    public ValueNode(String value) {
+        this.value = value;
+    }
+    
+    @Override
+    protected void dump(String space) {
+        System.out.println(space + value);
+    }
+
+    @Override
+    public String toString() {
+        return value;
+    }
+}
diff --git a/gotoSCons/src/main/java/org/apache/opeonoffice/gotoSCons/targets/BaseBinary.java b/gotoSCons/src/main/java/org/apache/opeonoffice/gotoSCons/targets/BaseBinary.java
new file mode 100644
index 0000000..874f61e
--- /dev/null
+++ b/gotoSCons/src/main/java/org/apache/opeonoffice/gotoSCons/targets/BaseBinary.java
@@ -0,0 +1,211 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package org.apache.opeonoffice.gotoSCons.targets;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.TreeSet;
+import org.apache.openoffice.gotoSCons.GBuildParser;
+import org.apache.openoffice.gotoSCons.Utils;
+import org.apache.openoffice.gotoSCons.raw.ListNode;
+
+public abstract class BaseBinary extends BaseTarget {
+    private File filename;
+    protected String name;
+    private Set<String> packageHeaders = new TreeSet<>();
+    private String precompiledHeader;
+    private Set<String> apis = new TreeSet<>();
+    private Set<String> defs = new TreeSet<>();
+    private Set<String> includes = new TreeSet<>();
+    private Set<String> exceptionObjects = new TreeSet<>();
+    private Set<String> noexceptionObjects = new TreeSet<>();
+    private Set<String> linkedLibs = new TreeSet<>();
+
+    public BaseBinary(File filename) throws Exception {
+        this.filename = filename;
+        try (
+                BufferedReader reader = new BufferedReader(new InputStreamReader(
+                        new FileInputStream(filename)))
+                ) {
+            ListNode rootNode = new GBuildParser().parse(reader);
+            parse(rootNode);
+        }
+    }
+
+    protected void parseAddApi(String[] args) throws Exception {
+        if (args.length != 2) {
+            throw new Exception("Expected 2 args, got " + Arrays.toString(args));
+        }
+        if (!args[0].equals(name)) {
+            throw new Exception("Target name isn't " + name);
+        }
+        for (String arg : Utils.spaceSeparatedTokens(args[1])) {
+            if (!apis.add(arg)) {
+                throw new Exception("Duplicate API " + arg);
+            }
+        }
+    }
+    
+    protected void parseAddDefs(String[] args) throws Exception {
+        if (args.length != 2) {
+            throw new Exception("Expected 2 args, got " + Arrays.toString(args));
+        }
+        if (!args[0].equals(name)) {
+            throw new Exception("Target name isn't " + name);
+        }
+        for (String arg : Utils.spaceSeparatedTokens(args[1])) {
+            if (!defs.add(arg)) {
+                throw new Exception("Duplicate def " + arg);
+            }
+        }
+    }
+    
+    protected void parseAddExceptionObjects(String[] args) throws Exception {
+        if (args.length != 2) {
+            throw new Exception("Expected 2 args, got " + Arrays.toString(args));
+        }
+        if (!args[0].equals(name)) {
+            throw new Exception("Target name isn't " + name);
+        }
+
+        for (String arg : Utils.spaceSeparatedTokens(args[1])) {
+            if (!exceptionObjects.add(arg)) {
+                throw new Exception("Duplicate exception object " + arg);
+            }
+        }
+    }
+
+    protected void parseAddNoExceptionObjects(String[] args) throws Exception {
+        if (args.length != 2) {
+            throw new Exception("Expected 2 args, got " + Arrays.toString(args));
+        }
+        if (!args[0].equals(name)) {
+            throw new Exception("Target name isn't " + name);
+        }
+
+        for (String arg : Utils.spaceSeparatedTokens(args[1])) {
+            if (!noexceptionObjects.add(arg)) {
+                throw new Exception("Duplicate noexception object " + arg);
+            }
+        }
+    }
+    
+    protected void parseAddLinkedLibs(String[] args) throws Exception {
+        if (args.length != 2) {
+            throw new Exception("Expected 2 args, got " + Arrays.toString(args));
+        }
+        if (!args[0].equals(name)) {
+            throw new Exception("Target name isn't " + name);
+        }
+
+        for (String arg : Utils.spaceSeparatedTokens(args[1])) {
+            if (!linkedLibs.add(arg)) {
+                throw new Exception("Duplicate linked lib " + arg);
+            }
+        }
+    }
+    
+    protected void parseAddPackageHeaders(String[] args) throws Exception {
+        if (args.length != 2) {
+            throw new Exception("Expected 2 args, got " + Arrays.toString(args));
+        }
+        if (!args[0].equals(name)) {
+            throw new Exception("Target name isn't " + name);
+        }
+
+        for (String arg : Utils.spaceSeparatedTokens(args[1])) {
+            if (!packageHeaders.add(arg)) {
+                throw new Exception("Duplicate package header " + arg);
+            }
+        }
+    }
+    
+    protected void parseAddPrecompiledHeader(String[] args) throws Exception {
+        if (args.length != 2) {
+            throw new Exception("Expected 2 args, got " + Arrays.toString(args));
+        }
+        if (!args[0].equals(name)) {
+            throw new Exception("Target name isn't " + name);
+        }
+        if (precompiledHeader != null) {
+            throw new Exception("Precompiled header already set");
+        } else {
+            precompiledHeader = args[1];
+        }
+    }
+    
+    protected void parseSetInclude(String[] args) throws Exception {
+        if (args.length != 2) {
+            throw new Exception("Expected 2 args, got " + Arrays.toString(args));
+        }
+        if (!args[0].equals(name)) {
+            throw new Exception("Target name isn't " + name);
+        }
+
+        for (String arg : Utils.spaceSeparatedTokens(args[1])) {
+            if (!includes.add(arg)) {
+                throw new Exception("Duplicate include " + arg);
+            }
+        }
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Set<String> getApis() {
+        return apis;
+    }
+
+    public Set<String> getDefs() {
+        return defs;
+    }
+
+    public Set<String> getExceptionObjects() {
+        return exceptionObjects;
+    }
+
+    public Set<String> getIncludes() {
+        return includes;
+    }
+
+    public Set<String> getLinkedLibs() {
+        return linkedLibs;
+    }
+
+    public Set<String> getNoexceptionObjects() {
+        return noexceptionObjects;
+    }
+
+    public Set<String> getPackageHeaders() {
+        return packageHeaders;
+    }
+
+    public String getPrecompiledHeader() {
+        return precompiledHeader;
+    }
+
+}
diff --git a/gotoSCons/src/main/java/org/apache/opeonoffice/gotoSCons/targets/BaseTarget.java b/gotoSCons/src/main/java/org/apache/opeonoffice/gotoSCons/targets/BaseTarget.java
new file mode 100644
index 0000000..b424ac9
--- /dev/null
+++ b/gotoSCons/src/main/java/org/apache/opeonoffice/gotoSCons/targets/BaseTarget.java
@@ -0,0 +1,59 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package org.apache.opeonoffice.gotoSCons.targets;
+
+import org.apache.openoffice.gotoSCons.raw.FunctionNode;
+import org.apache.openoffice.gotoSCons.raw.ListNode;
+import org.apache.openoffice.gotoSCons.raw.Node;
+
+public abstract class BaseTarget {
+    
+    protected void parse(ListNode root) throws Exception {
+        for (Node child : root.children) {
+            if (child instanceof FunctionNode) {
+                FunctionNode functionNode = (FunctionNode)child;
+                if (functionNode.function.equals("eval")) {
+                    parseEval(functionNode);
+                } else {
+                    throw new Exception("Top-level function isn't \"eval\" but \"" + functionNode.function + "\"");
+                }
+            } else {
+                throw new Exception("Top-level declaration isn't a function but " + child.toString());
+            }
+        }
+    }
+    
+    protected void parseEval(FunctionNode functionNode) throws Exception {
+        if (functionNode.child instanceof FunctionNode) {
+            FunctionNode nestedFunction = (FunctionNode)functionNode.child;
+            if (nestedFunction.function.equals("call")) {
+                parseCall(nestedFunction.child);
+            } else {
+                throw new Exception("eval's nested function isn't \"call\" but \"" + functionNode.function + "\"");
+            }
+        } else {
+            throw new Exception("eval child not a function but " + functionNode.child.toString());
+        }
+    }
+
+    abstract protected void parseCall(Node child) throws Exception;
+}
diff --git a/gotoSCons/src/main/java/org/apache/opeonoffice/gotoSCons/targets/Executable.java b/gotoSCons/src/main/java/org/apache/opeonoffice/gotoSCons/targets/Executable.java
new file mode 100644
index 0000000..09c52d3
--- /dev/null
+++ b/gotoSCons/src/main/java/org/apache/opeonoffice/gotoSCons/targets/Executable.java
@@ -0,0 +1,107 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package org.apache.opeonoffice.gotoSCons.targets;
+
+import java.io.File;
+import java.util.Arrays;
+import org.apache.openoffice.gotoSCons.raw.Node;
+import org.apache.openoffice.gotoSCons.raw.ValueNode;
+
+public class Executable extends BaseBinary {
+    private boolean isTargetTypeSet;
+    private boolean isTargetTypeGUI;
+
+    public Executable(File filename) throws Exception {
+        super(filename);
+    }
+
+    @Override
+    protected void parseCall(Node argsNode) throws Exception {
+        if (argsNode instanceof ValueNode) {
+            String value = ((ValueNode)argsNode).value;
+            String[] tokens = value.split(",");
+            
+            String function = tokens[0].trim();
+            String[] args = Arrays.copyOfRange(tokens, 1, tokens.length);
+            
+            if (function.equals("gb_Executable_Executable")) {
+                parseExecutableExecutable(args);
+            } else if (function.equals("gb_Executable_add_api")) {
+                parseAddApi(args);
+            } else if (function.equals("gb_Executable_add_defs")) {
+                parseAddDefs(args);
+            } else if (function.equals("gb_Executable_add_exception_objects")) {
+                parseAddExceptionObjects(args);
+            } else if (function.equals("gb_Executable_add_noexception_objects")) {
+                parseAddNoExceptionObjects(args);
+            } else if (function.equals("gb_Executable_add_linked_libs")) {
+                parseAddLinkedLibs(args);
+            } else if (function.equals("gb_Executable_add_package_headers")) {
+                parseAddPackageHeaders(args);
+            } else if (function.equals("gb_Executable_add_precompiled_header")) {
+                parseAddPrecompiledHeader(args);
+            } else if (function.equals("gb_Executable_set_include")) {
+                parseSetInclude(args);
+            } else if (function.equals("gb_Executable_set_targettype_gui")) {
+                parseSetTargetTypeGUI(args);
+            } else {
+                throw new Exception("UNHANDLED FUNCTION " + function);
+            }
+        } else {
+            throw new Exception("Call args not a value");
+        }
+
+    }
+    
+    private void parseExecutableExecutable(String[] args) throws Exception {
+        if (args.length != 1) {
+            throw new Exception("Expected 1 arg, got " + Arrays.toString(args));
+        }
+        this.name = args[0];
+    }
+
+    private void parseSetTargetTypeGUI(String[] args) throws Exception {
+        if (args.length != 2) {
+            throw new Exception("Expected 2 args, got " + Arrays.toString(args));
+        }
+        if (!args[0].equals(name)) {
+            throw new Exception("Target name isn't " + name);
+        }
+        isTargetTypeSet = true;
+        String yesNo = args[1].trim();
+        if (yesNo.equals("YES")) {
+            isTargetTypeGUI = true;
+        } else if (yesNo.equals("NO")) {
+            isTargetTypeGUI = false;
+        } else {
+            throw new Exception("Target type GUI isn't YES or NO but " + yesNo);
+        }
+    }
+    
+    public boolean isTargetTypeSet() {
+        return isTargetTypeSet;
+    }
+
+    public boolean isIsTargetTypeGUI() {
+        return isTargetTypeGUI;
+    }
+}
diff --git a/gotoSCons/src/main/java/org/apache/opeonoffice/gotoSCons/targets/Library.java b/gotoSCons/src/main/java/org/apache/opeonoffice/gotoSCons/targets/Library.java
new file mode 100644
index 0000000..9e8f828
--- /dev/null
+++ b/gotoSCons/src/main/java/org/apache/opeonoffice/gotoSCons/targets/Library.java
@@ -0,0 +1,99 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package org.apache.opeonoffice.gotoSCons.targets;
+
+import java.io.File;
+import java.util.Arrays;
+import org.apache.openoffice.gotoSCons.raw.Node;
+import org.apache.openoffice.gotoSCons.raw.ValueNode;
+
+public class Library extends BaseBinary {
+    private File filename;
+    private String componentFile;
+    
+    public Library(File filename) throws Exception {
+        super(filename);
+    }
+    
+    @Override
+    protected void parseCall(Node argsNode) throws Exception {
+        if (argsNode instanceof ValueNode) {
+            String value = ((ValueNode)argsNode).value;
+            String[] tokens = value.split(",");
+            
+            String function = tokens[0].trim();
+            String[] args = Arrays.copyOfRange(tokens, 1, tokens.length);
+            
+            if (function.equals("gb_Library_Library")) {
+                parseLibraryLibrary(args);
+            } else if (function.equals("gb_Library_add_api")) {
+                parseAddApi(args);
+            } else if (function.equals("gb_Library_add_defs")) {
+                parseAddDefs(args);
+            } else if (function.equals("gb_Library_add_exception_objects")) {
+                parseAddExceptionObjects(args);
+            } else if (function.equals("gb_Library_add_noexception_objects")) {
+                parseAddNoExceptionObjects(args);
+            } else if (function.equals("gb_Library_add_linked_libs")) {
+                parseAddLinkedLibs(args);
+            } else if (function.equals("gb_Library_add_package_headers")) {
+                parseAddPackageHeaders(args);
+            } else if (function.equals("gb_Library_add_precompiled_header")) {
+                parseAddPrecompiledHeader(args);
+            } else if (function.equals("gb_Library_set_componentfile")) {
+                parseSetComponentFile(args);
+            } else if (function.equals("gb_Library_set_include")) {
+                parseSetInclude(args);
+            } else {
+                throw new Exception("UNHANDLED FUNCTION " + function);
+            }
+        } else {
+            throw new Exception("Call args not a value");
+        }
+    }
+    
+    private void parseLibraryLibrary(String[] args) throws Exception {
+        if (args.length != 1) {
+            throw new Exception("Expected 1 arg, got " + Arrays.toString(args));
+        }
+        this.name = args[0];
+    }
+
+    private void parseSetComponentFile(String[] args) throws Exception {
+        if (args.length != 2) {
+            throw new Exception("Expected 2 args, got " + Arrays.toString(args));
+        }
+        if (!args[0].equals(name)) {
+            throw new Exception("Library isn't " + name);
+        }
+
+        if (componentFile != null) {
+            throw new Exception("Component file already set");
+        } else {
+            componentFile = args[1];
+        }
+    }
+    
+    public String getComponentFile() {
+        return componentFile;
+    }
+}
diff --git a/gotoSCons/src/main/java/org/apache/opeonoffice/gotoSCons/targets/Module.java b/gotoSCons/src/main/java/org/apache/opeonoffice/gotoSCons/targets/Module.java
new file mode 100644
index 0000000..5d20234
--- /dev/null
+++ b/gotoSCons/src/main/java/org/apache/opeonoffice/gotoSCons/targets/Module.java
@@ -0,0 +1,138 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package org.apache.opeonoffice.gotoSCons.targets;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import org.apache.openoffice.gotoSCons.GBuildParser;
+import org.apache.openoffice.gotoSCons.Utils;
+import org.apache.openoffice.gotoSCons.raw.ListNode;
+import org.apache.openoffice.gotoSCons.raw.Node;
+import org.apache.openoffice.gotoSCons.raw.ValueNode;
+
+public class Module extends BaseTarget {
+    private File filename;
+    private String name;
+    private Map<String, Library> libraries = new TreeMap<>();
+    private Map<String, Executable> executables = new TreeMap<>();
+    private TreeSet<String> targets = new TreeSet<>();
+    private Map<String, Pkg> packages = new TreeMap<>();
+    
+    public Module(File filename) throws Exception {
+        this.filename = filename;
+        try (
+                BufferedReader reader = new BufferedReader(new InputStreamReader(
+                        new FileInputStream(filename)))
+                ) {
+            ListNode rootNode = new GBuildParser().parse(reader);
+            parse(rootNode);
+        }
+    }
+    
+    @Override
+    protected void parseCall(Node argsNode) throws Exception {
+        if (argsNode instanceof ValueNode) {
+            String value = ((ValueNode)argsNode).value;
+            String[] tokens = value.split(",");
+            
+            String function = tokens[0].trim();
+            String[] args = Arrays.copyOfRange(tokens, 1, tokens.length);
+            
+            if (function.equals("gb_Module_Module")) {
+                parseModuleModule(args);
+            } else if (function.equals("gb_Module_add_targets")) {
+                parseModuleAddTargets(args);
+            } else {
+                throw new Exception("Unhandled function " + function);
+            }
+        } else {
+            throw new Exception("Call args not a value");
+        }
+    }
+    
+    private void parseModuleModule(String[] args) throws Exception {
+        if (args.length != 1) {
+            throw new Exception("Expected 1 arg, got " + Arrays.toString(args));
+        }
+        this.name = args[0];
+    }
+    
+    private void parseModuleAddTargets(String[] args) throws Exception {
+        if (args.length != 2) {
+            throw new Exception("Expected 2 args, got " + Arrays.toString(args));
+        }
+        if (!args[0].equals(name)) {
+            throw new Exception("Module isn't " + name);
+        }
+        for (String arg : Utils.spaceSeparatedTokens(args[1])) {
+            if (arg.startsWith("Executable_")) {
+                Executable exe = new Executable(new File(filename.getParentFile(), arg + ".mk"));
+                if (executables.put(arg, exe) != null) {
+                    throw new Exception("Duplicate add of target " + arg);
+                }
+            } else if (arg.startsWith("Library_")) {
+                Library library = new Library(new File(filename.getParentFile(), arg + ".mk"));
+                if (libraries.put(arg, library) != null) {
+                    throw new Exception("Duplicate add of target " + arg);
+                }
+            } else if (arg.startsWith("Package_")) {
+                Pkg pkg = new Pkg(new File(filename.getParentFile(), arg + ".mk"));
+                if (packages.put(arg, pkg) != null) {
+                    throw new Exception("Duplicate add of target " + arg);
+                }
+            } else {
+                throw new Exception("Unsupported target " + arg);
+            }
+        }
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public File getFilename() {
+        return filename;
+    }
+    
+    public Map<String, Library> getLibraries() {
+        return libraries;
+    }
+
+    public Map<String, Executable> getExecutables() {
+        return executables;
+    }
+    
+    public Map<String, Pkg> getPackages() {
+        return packages;
+    }
+
+    @Override
+    public String toString() {
+        return "Module{" + "filename=" + filename + ", name=" + name + ", targets=" + targets + '}';
+    }
+}
diff --git a/gotoSCons/src/main/java/org/apache/opeonoffice/gotoSCons/targets/Pkg.java b/gotoSCons/src/main/java/org/apache/opeonoffice/gotoSCons/targets/Pkg.java
new file mode 100644
index 0000000..a9b85c6
--- /dev/null
+++ b/gotoSCons/src/main/java/org/apache/opeonoffice/gotoSCons/targets/Pkg.java
@@ -0,0 +1,101 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package org.apache.opeonoffice.gotoSCons.targets;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.TreeMap;
+import org.apache.openoffice.gotoSCons.GBuildParser;
+import org.apache.openoffice.gotoSCons.raw.ListNode;
+import org.apache.openoffice.gotoSCons.raw.Node;
+import org.apache.openoffice.gotoSCons.raw.ValueNode;
+
+public class Pkg extends BaseTarget {
+    private File filename;
+    private String name;
+    private String baseDir;
+    private Map<String, String> filesToFrom = new TreeMap<>();
+    
+    public Pkg(File filename) throws Exception {
+        this.filename = filename;
+        try (
+                BufferedReader reader = new BufferedReader(new InputStreamReader(
+                        new FileInputStream(filename)))
+                ) {
+            ListNode rootNode = new GBuildParser().parse(reader);
+            parse(rootNode);
+        }
+    }
+
+    @Override
+    protected void parseCall(Node argsNode) throws Exception {
+        if (argsNode instanceof ValueNode) {
+            String value = ((ValueNode)argsNode).value;
+            String[] tokens = value.split(",");
+            
+            String function = tokens[0].trim();
+            String[] args = Arrays.copyOfRange(tokens, 1, tokens.length);
+            
+            if (function.equals("gb_Package_Package")) {
+                parsePackagePackage(args);
+            } else if (function.equals("gb_Package_add_file")) {
+                parseAddFile(args);
+            } else {
+                throw new Exception("UNHANDLED FUNCTION " + function);
+            }
+        } else {
+            throw new Exception("Call args not a value");
+        }
+    }
+
+    private void parsePackagePackage(String[] args) throws Exception {
+        if (args.length != 2) {
+            throw new Exception("Expected 2 arg, got " + Arrays.toString(args));
+        }
+        this.name = args[0];
+        this.baseDir = args[1];
+    }
+
+    private void parseAddFile(String[] args) throws Exception {
+        if (args.length != 3) {
+            throw new Exception("Expected 3 args, got " + Arrays.toString(args));
+        }
+        if (!args[0].equals(name)) {
+            throw new Exception("Package isn't " + name);
+        }
+        if (filesToFrom.put(args[1], args[2]) != null) {
+            throw new Exception("Duplicate package of file " + args[2] + " to " + args[1]);
+        }
+    }
+
+    public String getBaseDir() {
+        return baseDir;
+    }
+
+    public Map<String, String> getFilesToFrom() {
+        return filesToFrom;
+    }
+}
diff --git a/gotoSCons/src/main/java/org/apache/opeonoffice/gotoSCons/targets/Repository.java b/gotoSCons/src/main/java/org/apache/opeonoffice/gotoSCons/targets/Repository.java
new file mode 100644
index 0000000..5157ccd
--- /dev/null
+++ b/gotoSCons/src/main/java/org/apache/opeonoffice/gotoSCons/targets/Repository.java
@@ -0,0 +1,134 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+package org.apache.opeonoffice.gotoSCons.targets;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.TreeMap;
+import org.apache.openoffice.gotoSCons.GBuildParser;
+import org.apache.openoffice.gotoSCons.Utils;
+import org.apache.openoffice.gotoSCons.raw.ListNode;
+import org.apache.openoffice.gotoSCons.raw.Node;
+import org.apache.openoffice.gotoSCons.raw.ValueNode;
+
+public class Repository extends BaseTarget {
+    private File filename;
+    private String name;
+    private Map<String, String> libraryLayers = new TreeMap<>();
+    private Map<String, String> executableLayers = new TreeMap<>();
+    private Map<String, String> staticLibraryLayers = new TreeMap<>();
+    
+    public Repository(File filename) throws Exception {
+        this.filename = filename;
+        try (
+                BufferedReader reader = new BufferedReader(new InputStreamReader(
+                        new FileInputStream(filename)))
+                ) {
+            ListNode rootNode = new GBuildParser().parse(reader);
+            parse(rootNode);
+        }
+    }
+    
+    @Override
+    protected void parseCall(Node argsNode) throws Exception {
+        if (argsNode instanceof ValueNode) {
+            String value = ((ValueNode)argsNode).value;
+            String[] tokens = value.split(",");
+            
+            String function = tokens[0];
+            String[] args = Arrays.copyOfRange(tokens, 1, tokens.length);
+            
+            if (function.equals("gb_Helper_register_repository")) {
+                parseRegisterRepository(args);
+            } else if (function.equals("gb_Helper_register_executables")) {
+                parseRegisterExecutables(args);
+            } else if (function.equals("gb_Helper_register_libraries")) {
+                parseRegisterLibraries(args);
+            } else if (function.equals("gb_Helper_register_static_libraries")) {
+                parseRegisterStaticLibraries(args);
+            } else {
+                throw new Exception("Unhandled function " + function);
+            }
+        } else {
+            throw new Exception("Call args not a value");
+        }
+    }
+
+    private void parseRegisterRepository(String[] args) throws Exception {
+        if (args.length != 1) {
+            throw new Exception("Expected 1 arg, got " + args);
+        }
+        this.name = args[0];
+    }    
+    
+    private void parseRegisterExecutables(String[] args) throws Exception {
+        if (args.length != 2) {
+            throw new Exception("Expected 2 args, got " + args);
+        }
+        String layer = args[0];
+        for (String arg : Utils.spaceSeparatedTokens(args[1])) {
+            if (executableLayers.put(arg, layer) != null) {
+                throw new Exception("Duplicate executable " + arg);
+            }
+        }
+    }
+
+    private void parseRegisterLibraries(String[] args) throws Exception {
+        if (args.length != 2) {
+            throw new Exception("Expected 2 args, got " + args);
+        }
+        String layer = args[0];
+        for (String arg : Utils.spaceSeparatedTokens(args[1])) {
+            if (libraryLayers.put(arg, layer) != null) {
+                throw new Exception("Duplicate librarry " + arg);
+            }
+        }
+    }
+
+    private void parseRegisterStaticLibraries(String[] args) throws Exception {
+        if (args.length != 2) {
+            throw new Exception("Expected 2 args, got " + args);
+        }
+        String layer = args[0];
+        for (String arg : Utils.spaceSeparatedTokens(args[1])) {
+            if (staticLibraryLayers.put(arg, layer) != null) {
+                throw new Exception("Duplicate librarry " + arg);
+            }
+        }
+    }
+    
+    public String getExecutableLayer(String executable) {
+        return executableLayers.get(executable);
+    }
+    
+    public String getLibraryLayer(String library) {
+        return libraryLayers.get(library);
+    }
+    
+    public String getStaticLibraryLayer(String library) {
+        return staticLibraryLayers.get(library);
+    }
+}