258
src/Visual_DVM_2021/Passes/All/Precompilation.java
Normal file
258
src/Visual_DVM_2021/Passes/All/Precompilation.java
Normal file
@@ -0,0 +1,258 @@
|
||||
package Visual_DVM_2021.Passes.All;
|
||||
import Common.Constants;
|
||||
import Common.Current;
|
||||
import Common.Global;
|
||||
import Common.UI.UI;
|
||||
import Common.Utils.Utils;
|
||||
import GlobalData.Compiler.Compiler;
|
||||
import GlobalData.Compiler.CompilerType;
|
||||
import GlobalData.Makefile.Makefile;
|
||||
import GlobalData.Module.Module;
|
||||
import GlobalData.Settings.SettingName;
|
||||
import ProjectData.Files.DBProjectFile;
|
||||
import ProjectData.LanguageName;
|
||||
import ProjectData.Project.db_project_info;
|
||||
import Visual_DVM_2021.Passes.PassCode_2021;
|
||||
import Visual_DVM_2021.Passes.PassException;
|
||||
import Visual_DVM_2021.Passes.Pass_2021;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Vector;
|
||||
public class Precompilation extends Pass_2021<db_project_info> {
|
||||
protected static String name_to_kill = "";
|
||||
protected static boolean killed = false;
|
||||
protected String makepath;
|
||||
//----------------------->>>
|
||||
protected File workspace; //рабочая папка.
|
||||
protected Compiler fortranCompiler;
|
||||
protected Makefile makefile;
|
||||
protected File makefileFile;
|
||||
protected int performanceTime;
|
||||
protected int exitCode;
|
||||
//----------------------->>>
|
||||
protected Process process = null;
|
||||
protected String output = "";
|
||||
protected Vector<String> outputLines = new Vector<>();
|
||||
@Override
|
||||
protected boolean needsAnimation() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
protected boolean canStart(Object... args) throws Exception {
|
||||
target = Current.getProject();
|
||||
if (Global.isWindows) {
|
||||
//--
|
||||
makepath = Global.db.settings.get(SettingName.LocalMakePathWindows).toString();
|
||||
if (makepath.isEmpty()) {
|
||||
Log.Writeln_("Не задан путь к make.exe.\n " +
|
||||
"Укажите его в меню глобальных настроек." +
|
||||
"\nПредварительная компиляция будет отключена.");
|
||||
passes.get(PassCode_2021.UpdateSetting).Do(SettingName.Precompilation, "0");
|
||||
return false;
|
||||
}
|
||||
if (!(new File(makepath).exists())) {
|
||||
Log.Writeln_("Файла по пути к make.exe не существует.\n" +
|
||||
"Проверьте правильность его указания в глобальных настройках."+
|
||||
"\nПредварительная компиляция будет отключена.");
|
||||
passes.get(PassCode_2021.UpdateSetting).Do(SettingName.Precompilation, "0");
|
||||
return false;
|
||||
}
|
||||
//--
|
||||
}
|
||||
process = null;
|
||||
if (!target.languageName.equals(LanguageName.fortran)) {
|
||||
Log.Writeln_("Предварительная компиляция поддерживается только для FORTRAN.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
protected String getLinkFlags() {
|
||||
return "";
|
||||
}
|
||||
protected String getFortranFlags() {
|
||||
return "";
|
||||
}
|
||||
protected void prepareForParse() throws Exception {
|
||||
target.CleanAnalyses();
|
||||
}
|
||||
@Override
|
||||
protected void performPreparation() throws Exception {
|
||||
target.CleanInterruptFile();
|
||||
//-
|
||||
passes.get(PassCode_2021.Save).Do(); //---->
|
||||
prepareForParse(); //---->
|
||||
//-
|
||||
performanceTime = 0;
|
||||
exitCode = Constants.Nan;
|
||||
//------------------
|
||||
workspace = Paths.get(Global.TempDirectory.getAbsolutePath(), Utils.getDateName("precompilation")).toFile();
|
||||
FileUtils.forceMkdir(workspace);
|
||||
//------------------------------>>
|
||||
fortranCompiler = new Compiler();
|
||||
fortranCompiler.call_command = "gfortran";
|
||||
fortranCompiler.type = CompilerType.gnu;
|
||||
makefileFile = Paths.get(workspace.getAbsolutePath(), "Makefile").toFile();
|
||||
makefile = new Makefile() {
|
||||
@Override
|
||||
public Compiler getCompiler() {
|
||||
return fortranCompiler;
|
||||
}
|
||||
};
|
||||
makefile.flags = getLinkFlags();
|
||||
LinkedHashMap<LanguageName, Module> modules = new LinkedHashMap<>();
|
||||
Module fortranModule = new Module(LanguageName.fortran, null) {
|
||||
@Override
|
||||
public boolean isSelected() {
|
||||
return true; //всегда выбран. нужно для генерации.
|
||||
}
|
||||
@Override
|
||||
public Compiler getCompiler() {
|
||||
return fortranCompiler;
|
||||
}
|
||||
};
|
||||
fortranModule.flags = getFortranFlags();
|
||||
modules.put(LanguageName.fortran, fortranModule);
|
||||
//------------------------------>>
|
||||
target.Clone(workspace, false);
|
||||
//------------------------------>>
|
||||
FileUtils.write(makefileFile, genMakefileText(modules));
|
||||
//---
|
||||
}
|
||||
protected String genMakefileText(LinkedHashMap<LanguageName, Module> modules) throws Exception {
|
||||
return makefile.GenerateForPrecompilation(target, modules);
|
||||
}
|
||||
@Override
|
||||
protected void showPreparation() throws Exception {
|
||||
UI.getMainWindow().getProjectWindow().ShowNoAnalyses();
|
||||
if (Current.HasFile()) {
|
||||
Current.getFile().form.ShowNoMessages();
|
||||
Current.getFile().form.ShowNoAnalyses();
|
||||
}
|
||||
}
|
||||
protected static void unpackPrecompilationMessages(db_project_info target, String text) throws Exception {
|
||||
boolean messageStarted = false;
|
||||
String messageFile = "";
|
||||
int messageLine = Constants.Nan;
|
||||
int messageType = Constants.Nan;
|
||||
Vector<String> messageText = new Vector<>();
|
||||
String[] nw = text.split("\n");
|
||||
for (String S : nw) {
|
||||
if (messageStarted) {
|
||||
String s = S.toLowerCase();
|
||||
if (s.startsWith("warning:")) {
|
||||
messageText.add(S.substring(9));
|
||||
messageType = 0;
|
||||
} else if (s.startsWith("error:")) {
|
||||
messageText.add(S.substring(7));
|
||||
messageType = 1;
|
||||
} else if (s.startsWith("note:")) {
|
||||
messageText.add(S.substring(6));
|
||||
messageType = 2;
|
||||
}
|
||||
if (messageType != Constants.Nan) {
|
||||
target.db.files.Data.get(messageFile).CreateAndAddNewMessage(messageType, String.join("\n", messageText), messageLine, Constants.compiler_group);
|
||||
messageStarted = false;
|
||||
} else {
|
||||
if (!S.isEmpty())
|
||||
messageText.add(S);
|
||||
}
|
||||
} else {
|
||||
//анализ начала строки.
|
||||
for (String name : target.db.files.Data.keySet()) {
|
||||
if (S.startsWith(Utils.toU(name))) {
|
||||
String[] data = S.split(":");
|
||||
if (data.length > 1) {
|
||||
messageFile = name;
|
||||
messageLine = Integer.parseInt(data[1]);
|
||||
messageType = Constants.Nan;
|
||||
messageText = new Vector<>();
|
||||
messageStarted = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void body() throws Exception {
|
||||
if (Global.isWindows) {
|
||||
name_to_kill = "make.exe";
|
||||
StartProcess(Utils.DQuotes(Global.db.settings.get(SettingName.LocalMakePathWindows).Value) + " -j " + Global.db.settings.get(SettingName.Kernels).toString(),
|
||||
target.compilation_maxtime);
|
||||
} else
|
||||
StartProcess("make -j " + Global.db.settings.get(SettingName.Kernels).toString(), target.compilation_maxtime);
|
||||
}
|
||||
protected void StartProcess(String command, int TA) throws Exception {
|
||||
killed = false;
|
||||
output = "";
|
||||
process = Utils.startScript(workspace, workspace, Utils.getDateName("start_task_script"),
|
||||
command,
|
||||
null);
|
||||
outputLines.clear();
|
||||
InputStream stdout = process.getInputStream();
|
||||
InputStreamReader isrStdout = new InputStreamReader(stdout);
|
||||
BufferedReader brStdout = new BufferedReader(isrStdout);
|
||||
String line;
|
||||
//-
|
||||
while ((line = brStdout.readLine()) != null) {
|
||||
ShowMessage2(line);
|
||||
outputLines.add(line);
|
||||
}
|
||||
output = String.join("\n", outputLines);
|
||||
if (killed) {
|
||||
throw new PassException("Процесс был убит");
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected boolean validate() {
|
||||
return outputLines.stream().noneMatch(line -> line.toLowerCase().startsWith("error"));
|
||||
}
|
||||
@Override
|
||||
protected void performDone() throws Exception {
|
||||
System.out.println("DONE");
|
||||
}
|
||||
@Override
|
||||
protected void performFinish() throws Exception {
|
||||
for (DBProjectFile file : target.db.files.Data.values()) {
|
||||
if (!file.last_assembly_name.isEmpty()) {
|
||||
String replacement = file.last_assembly_name + " " + Utils.RBrackets(file.name);
|
||||
output = output.replace(file.last_assembly_name, replacement);
|
||||
}
|
||||
}
|
||||
target.updateCompilationOut(output);
|
||||
//----------------------------------
|
||||
target.db.BeginTransaction();
|
||||
unpackPrecompilationMessages(target, output);
|
||||
for (DBProjectFile file : target.db.files.Data.values())
|
||||
file.father.db.Update(file);
|
||||
target.db.Commit();
|
||||
//----------------------------------
|
||||
}
|
||||
@Override
|
||||
protected void showFinish() throws Exception {
|
||||
UI.getMainWindow().getProjectWindow().RefreshProjectTreeAndMessages();
|
||||
if (Current.HasFile())
|
||||
Current.getFile().form.ShowCompilationOutput();
|
||||
}
|
||||
@Override
|
||||
public void Interrupt() throws Exception {
|
||||
if (Global.isWindows) {
|
||||
if (!name_to_kill.isEmpty()) {
|
||||
killed = true;
|
||||
System.out.println("time to kill...");
|
||||
Process killer = Runtime.getRuntime().exec("taskkill /FI \"IMAGENAME eq " + name_to_kill + "\" /F /T");
|
||||
killer.waitFor();
|
||||
System.out.println("DEAD");
|
||||
}
|
||||
} else {
|
||||
UI.Info("Прерывание процессов под Linux не реализовано");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user