You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

173 lines
4.7 KiB
C++

/**
* @file code.cpp
* @brief Functionality for compiling and disassembling source code.
*
* Copyright (C) 2022 Clyne Sullivan
*
* Distributed under the GNU GPL v3 or later. You should have received a copy of
* the GNU General Public License along with this program.
* If not, see <https://www.gnu.org/licenses/>.
*/
#include "main.hpp"
#include "stmdsp.hpp"
#include "stmdsp_code.hpp"
#include <cstdio>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <memory>
#include <string>
extern std::shared_ptr<stmdsp::device> m_device;
// Stores the temporary file name currently used for compiling the algorithm.
static std::string tempFileName;
/**
* Generates a new temporary file name.
* @return A string containing the path and file name.
*/
static std::string newTempFileName();
/**
* Executes the given command using system(), collecting the text output in the
* given file.
* @param command The command to be executed.
* @param file The file to write command output to.
* @return True if the command was successful (i.e. returned zero).
*/
static bool codeExecuteCommand(const std::string& command, const std::string& file);
/**
* Does an in-place replacement of all occurances of "what" with "with".
* @param str The text string to operate on.
* @param what The text to search for.
* @param with The text that will replace occurances of "what".
*/
static void stringReplaceAll(std::string& str, const std::string& what,
const std::string& with);
std::ifstream compileOpenBinaryFile()
{
if (!tempFileName.empty())
return std::ifstream(tempFileName + ".o");
else
return std::ifstream();
}
void compileEditorCode(const std::string& code)
{
log("Compiling...");
if (tempFileName.empty()) {
tempFileName = newTempFileName();
} else {
std::filesystem::remove(tempFileName + ".o");
std::filesystem::remove(tempFileName + ".orig.o");
}
const auto platform = m_device ? m_device->get_platform()
: stmdsp::platform::L4;
{
std::ofstream file (tempFileName, std::ios::trunc | std::ios::binary);
auto file_text =
platform == stmdsp::platform::L4 ? stmdsp::file_header_l4
: stmdsp::file_header_h7;
const auto buffer_size = m_device ? m_device->get_buffer_size()
: stmdsp::SAMPLES_MAX;
stringReplaceAll(file_text, "$0", std::to_string(buffer_size));
file << file_text << '\n' << code;
}
const auto scriptFile = tempFileName +
#ifndef STMDSP_WIN32
".sh";
#else
".bat";
#endif
{
std::ofstream makefile (scriptFile, std::ios::binary);
auto make_text =
platform == stmdsp::platform::L4 ? stmdsp::makefile_text_l4
: stmdsp::makefile_text_h7;
stringReplaceAll(make_text, "$0", tempFileName);
stringReplaceAll(make_text, "$1",
std::filesystem::current_path().string());
makefile << make_text;
}
#ifndef STMDSP_WIN32
system((std::string("chmod +x ") + scriptFile).c_str());
#endif
const auto makeOutput = scriptFile + ".log";
const auto makeCommand = scriptFile + " > " + makeOutput + " 2>&1";
if (codeExecuteCommand(makeCommand, makeOutput))
log("Compilation succeeded.");
else
log("Compilation failed.");
std::filesystem::remove(tempFileName);
std::filesystem::remove(scriptFile);
}
void disassembleCode()
{
log("Disassembling...");
//if (tempFileName.empty())
// compileEditorCode();
const auto output = tempFileName + ".asm.log";
const auto command =
std::string("arm-none-eabi-objdump -d --no-show-raw-insn ") +
tempFileName + ".orig.o > " + output + " 2>&1";
if (codeExecuteCommand(command, output))
log("Ready.");
else
log("Failed to load disassembly.");
}
std::string newTempFileName()
{
const auto path = std::filesystem::temp_directory_path() / "stmdspgui_build";
return path.string();
}
bool codeExecuteCommand(const std::string& command, const std::string& file)
{
bool success = system(command.c_str()) == 0;
if (std::ifstream output (file); output.good()) {
std::ostringstream sstr;
sstr << output.rdbuf();
log(sstr.str().c_str());
} else {
log("Could not read command output!");
}
std::filesystem::remove(file);
return success;
}
void stringReplaceAll(std::string& str, const std::string& what, const std::string& with)
{
std::size_t i;
while ((i = str.find(what)) != std::string::npos) {
str.replace(i, what.size(), with);
i += what.size();
}
};