generator.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  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. }
  40. void generateCompilationScript(SessionContext &input, const ReadableString &scriptPath) {
  41. printText(U"Generating build script\n");
  42. String generatedCode;
  43. ScriptLanguage language = identifyLanguage(scriptPath);
  44. if (language == ScriptLanguage::Batch) {
  45. string_append(generatedCode, U"@echo off\n\n");
  46. } else if (language == ScriptLanguage::Bash) {
  47. string_append(generatedCode, U"#!/bin/bash\n\n");
  48. }
  49. // Keep track of the current path, so that it only changes when needed.
  50. String currentPath;
  51. // Generate code for compiling source code into objects.
  52. printText(U"Generating code for compiling ", input.sourceObjects.length(), U" objects.\n");
  53. for (int64_t o = 0; o < input.sourceObjects.length(); o++) {
  54. SourceObject *sourceObject = &(input.sourceObjects[o]);
  55. printText(U"\t* ", sourceObject->sourcePath, U"\n");
  56. setCompilationFolder(generatedCode, language, currentPath, sourceObject->compileFrom);
  57. if (language == ScriptLanguage::Batch) {
  58. string_append(generatedCode, U"if exist ", sourceObject->objectPath, U" (\n");
  59. } else if (language == ScriptLanguage::Bash) {
  60. string_append(generatedCode, U"if [ -e \"", sourceObject->objectPath, U"\" ]; then\n");
  61. }
  62. script_printMessage(generatedCode, language, string_combine(U"Reusing ", sourceObject->sourcePath, U" ID:", sourceObject->identityChecksum, U"."));
  63. if (language == ScriptLanguage::Batch) {
  64. string_append(generatedCode, U") else (\n");
  65. } else if (language == ScriptLanguage::Bash) {
  66. string_append(generatedCode, U"else\n");
  67. }
  68. String compilerFlags = sourceObject->generatedCompilerFlags;
  69. script_printMessage(generatedCode, language, string_combine(U"Compiling ", sourceObject->sourcePath, U" ID:", sourceObject->identityChecksum, U" with ", compilerFlags, U"."));
  70. string_append(generatedCode, sourceObject->compilerName, compilerFlags, U" -c ", sourceObject->sourcePath, U" -o ", sourceObject->objectPath, U"\n");
  71. if (language == ScriptLanguage::Batch) {
  72. string_append(generatedCode, ")\n");
  73. } else if (language == ScriptLanguage::Bash) {
  74. string_append(generatedCode, U"fi\n");
  75. }
  76. }
  77. // Generate code for linking objects into executables.
  78. printText(U"Generating code for linking ", input.linkerSteps.length(), U" executables:\n");
  79. for (int64_t l = 0; l < input.linkerSteps.length(); l++) {
  80. LinkingStep *linkingStep = &(input.linkerSteps[l]);
  81. String programPath = linkingStep->binaryName;
  82. printText(U"\tGenerating code for linking ", programPath, U" of :\n");
  83. setCompilationFolder(generatedCode, language, currentPath, linkingStep->compileFrom);
  84. String linkerFlags;
  85. for (int64_t lib = 0; lib < linkingStep->linkerFlags.length(); lib++) {
  86. String library = linkingStep->linkerFlags[lib];
  87. string_append(linkerFlags, " -l", library);
  88. printText(U"\t\t* ", library, U" library\n");
  89. }
  90. // Generate a list of object paths from indices.
  91. String allObjects;
  92. for (int64_t i = 0; i < linkingStep->sourceObjectIndices.length(); i++) {
  93. int64_t objectIndex = linkingStep->sourceObjectIndices[i];
  94. SourceObject *sourceObject = &(input.sourceObjects[objectIndex]);
  95. if (objectIndex >= 0 || objectIndex < input.sourceObjects.length()) {
  96. printText(U"\t\t* ", sourceObject->sourcePath, U"\n");
  97. string_append(allObjects, U" ", sourceObject->objectPath);
  98. } else {
  99. throwError(U"Object index ", objectIndex, U" is out of bound ", 0, U"..", (input.sourceObjects.length() - 1), U"\n");
  100. }
  101. }
  102. // Generate the code for building.
  103. if (string_length(linkerFlags) > 0) {
  104. script_printMessage(generatedCode, language, string_combine(U"Linking ", programPath, U" with", linkerFlags, U"."));
  105. } else {
  106. script_printMessage(generatedCode, language, string_combine(U"Linking ", programPath, U"."));
  107. }
  108. string_append(generatedCode, linkingStep->compilerName, allObjects, linkerFlags, U" -o ", programPath, U"\n");
  109. if (linkingStep->executeResult) {
  110. script_printMessage(generatedCode, language, string_combine(U"Starting ", programPath));
  111. string_append(generatedCode, programPath, U"\n");
  112. script_printMessage(generatedCode, language, U"The program terminated.");
  113. }
  114. }
  115. setCompilationFolder(generatedCode, language, currentPath, U"");
  116. script_printMessage(generatedCode, language, U"Done building.");
  117. // Save the script.
  118. printText(U"Saving script to ", scriptPath, "\n");
  119. if (language == ScriptLanguage::Batch) {
  120. string_save(scriptPath, generatedCode);
  121. } else if (language == ScriptLanguage::Bash) {
  122. string_save(scriptPath, generatedCode, CharacterEncoding::BOM_UTF8, LineEncoding::Lf);
  123. }
  124. }