215 lines
6.4 KiB
C++
215 lines
6.4 KiB
C++
#include "grbc/ext_cmake.h"
|
|
#include "grbc/cJSON.h"
|
|
#include "grbc/ext.h"
|
|
#include "grbc/helpers.h"
|
|
#include "grbc/spec.h"
|
|
#include "sol/raii.hpp"
|
|
#include <cstdlib>
|
|
#include <filesystem>
|
|
|
|
std::filesystem::path cmake_eval_symlink(const std::filesystem::path &build_dir,
|
|
const std::filesystem::path &path) {
|
|
std::filesystem::path c_path = path;
|
|
|
|
while (std::filesystem::is_symlink(c_path)) {
|
|
c_path = std::filesystem::read_symlink(c_path);
|
|
|
|
// Make path absolute if its relative
|
|
if (c_path.is_relative())
|
|
c_path = path.parent_path() / c_path;
|
|
|
|
std::filesystem::path target_path = build_dir / c_path.filename();
|
|
|
|
if (std::filesystem::exists(target_path))
|
|
std::filesystem::remove(target_path);
|
|
|
|
std::filesystem::copy(c_path, target_path);
|
|
}
|
|
|
|
return c_path;
|
|
}
|
|
|
|
std::string cmake_util_read_file(FILE *file) {
|
|
// http://www.fundza.com/c4serious/fileIO_reading_all/index.html
|
|
|
|
char line[190];
|
|
std::string result;
|
|
|
|
while (fgets(line, 190, file))
|
|
result += line;
|
|
|
|
if (result.back() == '\n')
|
|
result.pop_back();
|
|
|
|
return result;
|
|
}
|
|
|
|
CMakeProject EXT_grbc_import_cmake(const std::string &cmake_path,
|
|
const CMakeConfig &cfg) {
|
|
CMakeProject project{};
|
|
|
|
log_msg(("configuring cmake project: " + cmake_path).c_str());
|
|
|
|
if (!std::filesystem::exists(cmake_path)) {
|
|
grbc_exception("CMake cannot configure in non-existant directory: " +
|
|
cmake_path);
|
|
}
|
|
|
|
if (!std::filesystem::exists(cmake_path + "/CMakeLists.txt")) {
|
|
grbc_exception("No CMakeLists.txt file in: " + cmake_path);
|
|
}
|
|
|
|
std::filesystem::path old_path = std::filesystem::current_path();
|
|
|
|
// Change directory into the cmake dir
|
|
std::filesystem::current_path(cmake_path);
|
|
|
|
std::filesystem::create_directory("grbc_configure");
|
|
|
|
std::filesystem::current_path("./grbc_configure");
|
|
|
|
project.build_dir = std::filesystem::current_path().string();
|
|
|
|
// Create configure arg string
|
|
std::string configure_arguments;
|
|
|
|
for (const std::string &argument : cfg.configure_arguments) {
|
|
configure_arguments += argument + " ";
|
|
}
|
|
|
|
// Run configure
|
|
int exit_code =
|
|
std::system(("cmake -S .. -B . -GNinja " + configure_arguments).c_str());
|
|
|
|
if (exit_code != EXIT_SUCCESS)
|
|
grbc_exception("Failed to configure cmake project in: " + cmake_path);
|
|
|
|
// Collect compilation database
|
|
FILE *compdb = popen("ninja -t compdb", "r");
|
|
std::string compdb_raw = cmake_util_read_file(compdb);
|
|
|
|
pclose(compdb);
|
|
|
|
project.compdb = cJSON_Parse(compdb_raw.c_str());
|
|
|
|
// Build the cmake subproject, we need this so we can copy artifacts later on in the build step
|
|
|
|
grbc_log("building cmake subproject...");
|
|
int build_exit_code = std::system("ninja");
|
|
|
|
if (build_exit_code != EXIT_SUCCESS)
|
|
grbc_exception("Failed to build cmake project in: " + project.build_dir);
|
|
|
|
std::filesystem::current_path(old_path);
|
|
|
|
|
|
return project;
|
|
}
|
|
|
|
Package EXT_grbc_get_cmake_library(const CMakeProject &self,
|
|
const std::string &library_name) {
|
|
|
|
// Loop over every output in the compdb
|
|
|
|
for (int i = 0; i < cJSON_GetArraySize(self.compdb); i++) {
|
|
cJSON *compdb_item = cJSON_GetArrayItem(self.compdb, i);
|
|
|
|
if (!cJSON_HasObjectItem(compdb_item, "output"))
|
|
grbc_exception("Ninja produced invalid compilation database!");
|
|
|
|
if (!cJSON_HasObjectItem(compdb_item, "command"))
|
|
grbc_exception("Compilation database item is missing 'command'");
|
|
|
|
if (!cJSON_HasObjectItem(compdb_item, "file"))
|
|
grbc_exception("Compilation database item is missing 'file'");
|
|
|
|
std::string command =
|
|
cJSON_GetStringValue(cJSON_GetObjectItem(compdb_item, "command"));
|
|
|
|
// Only handle objects with an empty command
|
|
// In the compilation databse objects with no command, but an output, and
|
|
// file give us the info we need Info needed: Target name, output name
|
|
|
|
if (!command.empty())
|
|
continue;
|
|
|
|
std::string output_name =
|
|
cJSON_GetStringValue(cJSON_GetObjectItem(compdb_item, "output"));
|
|
std::string library_path =
|
|
cJSON_GetStringValue(cJSON_GetObjectItem(compdb_item, "file"));
|
|
|
|
if (output_name != library_name)
|
|
continue;
|
|
|
|
std::filesystem::path full_lib_path = self.build_dir + "/" + library_path;
|
|
full_lib_path =
|
|
cmake_eval_symlink(grbc_get_config().build_dir, full_lib_path);
|
|
|
|
Package pkg{};
|
|
pkg.name = output_name;
|
|
pkg.linker_flags = grbc_get_config().build_dir + "/" + full_lib_path.filename().generic_string();
|
|
|
|
grbc_log("found cmake library at: " + full_lib_path.generic_string());
|
|
|
|
return pkg;
|
|
}
|
|
|
|
grbc_exception("Failed to find library with name: " + library_name);
|
|
|
|
return Package{};
|
|
}
|
|
|
|
std::string EXT_grbc_get_cmake_library_string(const CMakeProject &self) {
|
|
std::string library_string;
|
|
|
|
for (int i = 0; i < cJSON_GetArraySize(self.compdb); i++) {
|
|
cJSON *compdb_item = cJSON_GetArrayItem(self.compdb, i);
|
|
|
|
if (!cJSON_HasObjectItem(compdb_item, "output"))
|
|
grbc_exception("Ninja produced invalid compilation database!");
|
|
|
|
if (!cJSON_HasObjectItem(compdb_item, "command"))
|
|
grbc_exception("Compilation database item is missing 'command'");
|
|
|
|
if (!cJSON_HasObjectItem(compdb_item, "file"))
|
|
grbc_exception("Compilation database item is missing 'file'");
|
|
|
|
std::string cmd =
|
|
cJSON_GetStringValue(cJSON_GetObjectItem(compdb_item, "command"));
|
|
|
|
if (!cmd.empty())
|
|
continue;
|
|
|
|
std::string file =
|
|
cJSON_GetStringValue(cJSON_GetObjectItem(compdb_item, "file"));
|
|
std::string output =
|
|
cJSON_GetStringValue(cJSON_GetObjectItem(compdb_item, "output"));
|
|
|
|
library_string += "Target: " + output + "\n";
|
|
library_string += "\tOutputting to file: " + output + "\n\n";
|
|
}
|
|
|
|
return library_string;
|
|
}
|
|
|
|
void grbc_cmake_init(sol::state &lua) {
|
|
lua.new_usertype<CMakeConfig>(
|
|
"CMakeConfig", sol::constructors<CMakeConfig(sol::table)>(),
|
|
"configure_arguments", &CMakeConfig::configure_arguments);
|
|
lua.new_usertype<CMakeProject>("CMakeProject", "source_dir",
|
|
&CMakeProject::source_dir, "build_dir",
|
|
&CMakeProject::build_dir);
|
|
|
|
lua["CMakeProject"]["get_library"] = EXT_grbc_get_cmake_library;
|
|
lua["CMakeProject"]["get_library_string"] = EXT_grbc_get_cmake_library_string;
|
|
|
|
lua.set("grbc_import_cmake", EXT_grbc_import_cmake);
|
|
}
|
|
|
|
Extension grbc_cmake() {
|
|
Extension ext{};
|
|
ext.name = GRBC_EXT_cmake_NAME;
|
|
ext.hook_init = grbc_cmake_init;
|
|
|
|
return ext;
|
|
} |