// // Created by servostar on 6/4/24. // #include <llvm/link/lld.h> #include <sys/log.h> #include <mem/cache.h> #include <sys/col.h> const char* get_absolute_link_path(const TargetConfig* config, const char* link_target_name) { INFO("resolving absolute path for link target: %s", link_target_name); for (guint i = 0; i < config->link_search_paths->len; i++) { const char* link_directory_path = g_array_index(config->link_search_paths, char*, i); char* path = g_build_filename(link_directory_path, link_target_name, NULL); char* cwd = g_get_current_dir(); char* canonical = g_canonicalize_filename(path, cwd); const gboolean exists = g_file_test(canonical, G_FILE_TEST_EXISTS); const gboolean is_dir = g_file_test(canonical, G_FILE_TEST_IS_DIR); g_free(path); g_free(cwd); if (exists && !is_dir) { INFO("link target found at: %s", canonical); return canonical; } g_free(canonical); } // file not found return NULL; } TargetLinkConfig* lld_create_link_config(__attribute__((unused)) const Target* target, const TargetConfig* target_config, const Module* module) { DEBUG("generating link configuration"); TargetLinkConfig* config = mem_alloc(MemoryNamespaceLld, sizeof(TargetLinkConfig)); config->fatal_warnings = target_config->lld_fatal_warnings; config->object_file_names = g_array_new(FALSE, FALSE, sizeof(char*)); config->colorize = stdout_supports_ansi_esc(); // append build object file char* basename = g_strjoin(".", target_config->name, "o", NULL); char* filename = g_build_filename(target_config->archive_directory, basename, NULL); const char* target_object = get_absolute_link_path(target_config, (const char*) filename); if (target_object == NULL) { ERROR("failed to resolve path to target object: %s", filename); lld_delete_link_config(config); return NULL; } { // output file after linking basename = g_strjoin(".", target_config->name, "out", NULL); filename = g_build_filename(target_config->output_directory, basename, NULL); config->output_file = filename; } g_array_append_val(config->object_file_names, target_object); INFO("resolved path of target object: %s", target_object); // resolve absolute paths to dependent library object files DEBUG("resolving target dependencies..."); for (guint i = 0; i < module->imports->len; i++) { const char* dependency = g_array_index(module->imports, const char*, i); const char* library = g_strjoin("", "libgsc", dependency, ".a", NULL); const char* dependency_object = get_absolute_link_path(target_config, library); if (dependency_object == NULL) { ERROR("failed to resolve path to dependency object: %s", library); lld_delete_link_config(config); return NULL; } g_array_append_val(config->object_file_names, dependency_object); INFO("resolved path of target object: %s", dependency_object); } INFO("resolved %d dependencies", config->object_file_names->len); return config; } GArray* lld_create_lld_arguments(TargetLinkConfig* config) { GArray* argv = g_array_new(TRUE, FALSE, sizeof(char*)); gchar* arg = g_strdup("ld.lld"); g_array_append_val(argv, arg); if (config->fatal_warnings) { arg = g_strdup("--fatal-warnings"); g_array_append_val(argv, arg); } if (config->colorize) { arg = g_strdup("--color-diagnostics=always"); g_array_append_val(argv, arg); } { arg = g_strjoin("", "-o", config->output_file, NULL); g_array_append_val(argv, arg); } for (guint i = 0; i < config->object_file_names->len; i++) { char* object_file_path = g_array_index(config->object_file_names, char*, i); arg = g_strjoin("", object_file_path, NULL); g_array_append_val(argv, arg); } return argv; } BackendError lld_link_target(TargetLinkConfig* config) { DEBUG("linking target..."); BackendError err = SUCCESS; GArray* argv = lld_create_lld_arguments(config); INFO("Linking target..."); char* arguments = g_strjoinv(" ", (char**) argv->data); print_message(Info, "%s", arguments); g_free(arguments); INFO("done linking target..."); g_array_free(argv, TRUE); return err; } void lld_delete_link_config(TargetLinkConfig* config) { for (guint i = 0; i < config->object_file_names->len; i++) { free((void*) g_array_index(config->object_file_names, const char*, i)); } g_array_free(config->object_file_names, TRUE); mem_free(config); }