generator.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. 
  2. #include "generator.h"
  3. using namespace dsr;
  4. static ScriptLanguage identifyLanguage(const ReadableString &filename) {
  5. String scriptExtension = string_upperCase(file_getExtension(filename));
  6. if (string_match(scriptExtension, U"BAT")) {
  7. return ScriptLanguage::Batch;
  8. } else if (string_match(scriptExtension, U"SH")) {
  9. return ScriptLanguage::Bash;
  10. } else {
  11. throwError(U"Could not identify the scripting language of ", filename, U". Use *.bat or *.sh.\n");
  12. return ScriptLanguage::Unknown;
  13. }
  14. }
  15. static void script_printMessage(String &output, ScriptLanguage language, const ReadableString message) {
  16. if (language == ScriptLanguage::Batch) {
  17. string_append(output, U"echo ", message, U"\n");
  18. } else if (language == ScriptLanguage::Bash) {
  19. string_append(output, U"echo ", message, U"\n");
  20. }
  21. }
  22. static void setCompilationFolder(String &generatedCode, ScriptLanguage language, String &currentPath, const ReadableString &newPath) {
  23. if (!string_match(currentPath, newPath)) {
  24. if (string_length(currentPath) > 0) {
  25. if (language == ScriptLanguage::Batch) {
  26. string_append(generatedCode, "popd\n");
  27. } else if (language == ScriptLanguage::Bash) {
  28. string_append(generatedCode, U")\n");
  29. }
  30. }
  31. if (string_length(newPath) > 0) {
  32. if (language == ScriptLanguage::Batch) {
  33. string_append(generatedCode, "pushd ", newPath, "\n");
  34. } else if (language == ScriptLanguage::Bash) {
  35. string_append(generatedCode, U"(cd ", newPath, ";\n");
  36. }
  37. }
  38. }
  39. currentPath = newPath;
  40. }
  41. void generateCompilationScript(SessionContext &input, const ReadableString &scriptPath) {
  42. printText(U"Generating build script\n");
  43. String generatedCode;
  44. ScriptLanguage language = identifyLanguage(scriptPath);
  45. if (language == ScriptLanguage::Batch) {
  46. string_append(generatedCode, U"@echo off\n\n");
  47. } else if (language == ScriptLanguage::Bash) {
  48. string_append(generatedCode, U"#!/bin/bash\n\n");
  49. }
  50. // Keep track of the current path, so that it only changes when needed.
  51. String currentPath;
  52. // Generate code for compiling source code into objects.
  53. printText(U"Generating code for compiling ", input.sourceObjects.length(), U" objects.\n");
  54. for (int64_t o = 0; o < input.sourceObjects.length(); o++) {
  55. SourceObject *sourceObject = &(input.sourceObjects[o]);
  56. printText(U"\t* ", sourceObject->sourcePath, U"\n");
  57. setCompilationFolder(generatedCode, language, currentPath, sourceObject->compileFrom);
  58. if (language == ScriptLanguage::Batch) {
  59. string_append(generatedCode, U"if exist ", sourceObject->objectPath, U" (\n");
  60. } else if (language == ScriptLanguage::Bash) {
  61. string_append(generatedCode, U"if [ -e \"", sourceObject->objectPath, U"\" ]; then\n");
  62. }
  63. script_printMessage(generatedCode, language, string_combine(U"Reusing ", sourceObject->sourcePath, U" ID:", sourceObject->identityChecksum, U"."));
  64. if (language == ScriptLanguage::Batch) {
  65. string_append(generatedCode, U") else (\n");
  66. } else if (language == ScriptLanguage::Bash) {
  67. string_append(generatedCode, U"else\n");
  68. }
  69. String compilerFlags = sourceObject->generatedCompilerFlags;
  70. script_printMessage(generatedCode, language, string_combine(U"Compiling ", sourceObject->sourcePath, U" ID:", sourceObject->identityChecksum, U" with ", compilerFlags, U"."));
  71. string_append(generatedCode, sourceObject->compilerName, compilerFlags, U" -c ", sourceObject->sourcePath, U" -o ", sourceObject->objectPath, U"\n");
  72. if (language == ScriptLanguage::Batch) {
  73. string_append(generatedCode, ")\n");
  74. } else if (language == ScriptLanguage::Bash) {
  75. string_append(generatedCode, U"fi\n");
  76. }
  77. }
  78. // Generate code for linking objects into executables.
  79. printText(U"Generating code for linking ", input.linkerSteps.length(), U" executables:\n");
  80. for (int64_t l = 0; l < input.linkerSteps.length(); l++) {
  81. LinkingStep *linkingStep = &(input.linkerSteps[l]);
  82. String programPath = linkingStep->binaryName;
  83. printText(U"\tGenerating code for linking ", programPath, U" of :\n");
  84. setCompilationFolder(generatedCode, language, currentPath, linkingStep->compileFrom);
  85. String linkerFlags;
  86. for (int64_t lib = 0; lib < linkingStep->linkerFlags.length(); lib++) {
  87. String linkerFlag = linkingStep->linkerFlags[lib];
  88. string_append(linkerFlags, " ", linkerFlag);
  89. printText(U"\t\t* ", linkerFlag, U" library\n");
  90. }
  91. // Generate a list of object paths from indices.
  92. String allObjects;
  93. for (int64_t i = 0; i < linkingStep->sourceObjectIndices.length(); i++) {
  94. int64_t objectIndex = linkingStep->sourceObjectIndices[i];
  95. SourceObject *sourceObject = &(input.sourceObjects[objectIndex]);
  96. if (objectIndex >= 0 || objectIndex < input.sourceObjects.length()) {
  97. printText(U"\t\t* ", sourceObject->sourcePath, U"\n");
  98. string_append(allObjects, U" ", sourceObject->objectPath);
  99. } else {
  100. throwError(U"Object index ", objectIndex, U" is out of bound ", 0, U"..", (input.sourceObjects.length() - 1), U"\n");
  101. }
  102. }
  103. // Generate the code for building.
  104. if (string_length(linkerFlags) > 0) {
  105. script_printMessage(generatedCode, language, string_combine(U"Linking ", programPath, U" with", linkerFlags, U"."));
  106. } else {
  107. script_printMessage(generatedCode, language, string_combine(U"Linking ", programPath, U"."));
  108. }
  109. string_append(generatedCode, linkingStep->compilerName, allObjects, linkerFlags, U" -o ", programPath, U"\n");
  110. if (linkingStep->executeResult) {
  111. script_printMessage(generatedCode, language, string_combine(U"Starting ", programPath));
  112. string_append(generatedCode, programPath, U"\n");
  113. script_printMessage(generatedCode, language, U"The program terminated.");
  114. }
  115. }
  116. setCompilationFolder(generatedCode, language, currentPath, U"");
  117. script_printMessage(generatedCode, language, U"Done building.");
  118. // Save the script.
  119. printText(U"Saving script to ", scriptPath, "\n");
  120. if (language == ScriptLanguage::Batch) {
  121. string_save(scriptPath, generatedCode);
  122. } else if (language == ScriptLanguage::Bash) {
  123. string_save(scriptPath, generatedCode, CharacterEncoding::BOM_UTF8, LineEncoding::Lf);
  124. }
  125. }