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.
160 lines
4.2 KiB
C++
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();
|
|
}
|
|
};
|
|
|