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.
stmdspgui/source/code.cpp

160 lines
4.2 KiB
C++

/**
* @file code.cpp
* @brief Functionality for compiling and disassembling source code.
*
* Copyright (C) 2021 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 "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;
void log(const std::string& str);
std::ifstream compileOpenBinaryFile();
void compileEditorCode(const std::string& code);
void disassembleCode();
static std::string tempFileName;
static std::string newTempFileName();
static bool codeExecuteCommand(
const std::string& command,
const std::string& file);
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();
}
};