/* * CCompiler.java * * Copyright (C) 2015 Pixelgaffer * * This work is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation; either version 2 of the License, or any later * version. * * This work is distributed in the hope that it will be useful, but without * any warranty; without even the implied warranty of merchantability or * fitness for a particular purpose. See version 2 and version 3 of the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.pixelgaffer.turnierserver.compile; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Properties; import java.util.Set; import org.apache.commons.io.FileUtils; import org.pixelgaffer.turnierserver.compile.LibraryDownloader.LibraryDownloaderMode; import org.pixelgaffer.turnierserver.networking.DatastoreFtpClient; public class CCompiler extends Compiler { public CCompiler (int ai, int version, int game) { super(ai, version, game); } @Override public String getLanguage () { return "C"; } @Override public boolean compile (File srcdir, File bindir, Properties p, PrintWriter output, LibraryDownloader libs) throws IOException, InterruptedException { Set<File> librarys = new HashSet<>(), includepath = new HashSet<>(); includepath.add(srcdir); String librarypath; // die AiLibrary laden output.print("> Lade Ai Bibliothek herunter ... "); output.flush(); File libdir = new File(bindir, "AiLibrary"); librarypath = libdir.getName(); libdir.mkdir(); try { if (libs == null || libs.getMode() == LibraryDownloaderMode.LIBS_ONLY) DatastoreFtpClient.retrieveAiLibrary(getGame(), "C", libdir); else { for (File f : libs.getAiLibs("C")) FileUtils.copyFile(f, new File(libdir, f.getName())); } includepath.add(libdir); for (File so : libdir.listFiles( (dir, name) -> name.endsWith(".so"))) librarys.add(so); output.println("done"); } catch (Exception e) { libdir.delete(); output.println(e); return false; } // kompilieren getEnvironment().put("LD_LIBRARY_PATH", librarypath); Set<File> objects = new HashSet<>(); if (!compileRecursive(srcdir, p, librarys, includepath, srcdir, bindir, objects, output)) return false; // linken List<String> command = new LinkedList<>(); command.add("g++"); File exec = new File(bindir, "ai"); command.add("-o"); command.add(exec.getName()); if (Boolean.parseBoolean(p.getProperty("debug", "false"))) { command.add("-g"); command.add("-rdynamic"); } else command.add("-Wl,-O2"); for (File obj : objects) command.add(obj.getName()); command.add("-lm"); // math lib for (File lib : librarys) { command.add("-L" + lib.getParentFile().getAbsolutePath()); // cut of the trailing lib and the leading .so command.add("-l" + lib.getName().substring(3, lib.getName().length() - 3)); } int returncode = execute(bindir, output, command); if (returncode != 0) { output.println("Process finished with exit code " + returncode + ", aborting"); return false; } for (File obj : objects) // ich brauche die .o net mehr obj.delete(); setCommand("./" + exec.getName()); setArguments(new String[] {}); return true; } protected boolean compileRecursive (File currentDir, Properties p, Set<File> librarys, Set<File> includepath, File srcdir, File bindir, Set<File> objects, PrintWriter output) throws IOException, InterruptedException { for (String filename : currentDir.list()) { File file = new File(currentDir, filename); if (file.isDirectory()) { if (!compileRecursive(file, p, librarys, includepath, srcdir, bindir, objects, output)) return false; continue; } // .c, .cpp & .cxx -Dateien kompilieren if (filename.endsWith(".c") || filename.endsWith(".cpp") || filename.endsWith(".cxx")) { boolean c = filename.endsWith(".c"); List<String> command = new LinkedList<>(); command.add(c ? "gcc" : "g++"); if (filename.endsWith(".c")) command.add("-std=" + (p.getProperty("standart.c.gnu", "false").equalsIgnoreCase("true") ? "gnu" : "c") + p.getProperty("standart.c.version", "90")); else command.add("-std=" + (p.getProperty("standart.cpp.gnu", "false").equalsIgnoreCase("true") ? "gnu" : "c") + "++" + p.getProperty("standart.cpp.version", "98")); File out = new File(bindir, filename.substring(0, filename.lastIndexOf('.')) + ".o"); command.add("-o"); command.add(out.getName()); if (Boolean.parseBoolean(p.getProperty("debug", "false"))) command.add("-g"); else command.add("-O2"); command.add("-c"); command.add(file.getAbsolutePath()); for (File incpath : includepath) command.add("-I" + incpath.getAbsolutePath()); int returncode = execute(bindir, output, getEnvironment(), command); if (returncode != 0) { output.println("Process finished with exit code " + returncode + ", aborting"); return false; } objects.add(out); } else if (!filename.endsWith(".h") && !filename.endsWith(".hxx")) { // die Datei ins bindir kopieren String relative = relativePath(file, srcdir); copy(file, new File(bindir, relative)); } } return true; } }