1 // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors. 2 // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 3 // 4 // SPDX-License-Identifier: BSD-2-Clause 5 // 6 // This file is part of CEED: http://github.com/ceed 7 8 #include <ceed/ceed.h> 9 #include <ceed/backend.h> 10 #include <ceed/jit-tools.h> 11 #include <ceed-impl.h> 12 #include <stdbool.h> 13 #include <stdio.h> 14 #include <string.h> 15 16 /** 17 @brief Load source file into initalized string buffer, including full text 18 of local files in place of `#include "local.h"` 19 20 @param ceed A Ceed object for error handling 21 @param[in] source_file_path Absolute path to source file 22 @param[out] buffer String buffer for source file contents 23 24 @return An error code: 0 - success, otherwise - failure 25 26 @ref Backend 27 **/ 28 static inline int CeedLoadSourceToInitalizedBuffer(Ceed ceed, 29 const char *source_file_path, char **buffer) { 30 int ierr; 31 FILE *source_file; 32 long file_size, file_offset = 0; 33 char *temp_buffer; 34 35 // Debug 36 CeedDebug256(ceed, 1, "---------- Ceed JiT ----------\n"); 37 CeedDebug256(ceed, 1, "Current source file: "); 38 CeedDebug256(ceed, 255, "%s\n", source_file_path); 39 CeedDebug256(ceed, 1, "Current buffer:\n"); 40 CeedDebug256(ceed, 255, "%s\n", *buffer); 41 42 // Read file to temporary buffer 43 source_file = fopen(source_file_path, "rb"); 44 if (!source_file) 45 // LCOV_EXCL_START 46 return CeedError(ceed, CEED_ERROR_MAJOR, "Couldn't open source file: %s", 47 source_file_path); 48 // LCOV_EXCL_STOP 49 // -- Compute size of source 50 fseek(source_file, 0L, SEEK_END); 51 file_size = ftell(source_file); 52 rewind(source_file); 53 // -- Allocate memory for entire source file 54 ierr = CeedCalloc(file_size + 1, &temp_buffer); CeedChk(ierr); 55 // -- Copy the file into the buffer 56 if (1 != fread(temp_buffer, file_size, 1, source_file)) { 57 // LCOV_EXCL_START 58 fclose(source_file); 59 ierr = CeedFree(&temp_buffer); CeedChk(ierr); 60 return CeedError(ceed, CEED_ERROR_MAJOR, "Couldn't read source file: %s", 61 source_file_path); 62 // LCOV_EXCL_STOP 63 } 64 fclose(source_file); 65 66 // Search for headers to include 67 const char *first_hash = strchr(temp_buffer, '#'); 68 while (first_hash) { 69 // -- Check for 'include' keyword 70 const char *next_e = strchr(first_hash, 'e'); 71 char keyword[8] = ""; 72 if (next_e) 73 strncpy(keyword, &next_e[-6], 7); 74 bool is_hash_include = !strcmp(keyword, "include"); 75 // ---- Spaces allowed in '# include <header.h>' 76 if (next_e) 77 for (CeedInt i = 1; first_hash - next_e + i < -6; i++) 78 is_hash_include &= first_hash[i] == ' '; 79 if (is_hash_include) { 80 // -- Copy into buffer all preceding # 81 long current_size = strlen(*buffer); 82 long copy_size = first_hash - &temp_buffer[file_offset]; 83 ierr = CeedRealloc(current_size + copy_size + 2, buffer); CeedChk(ierr); 84 strncpy(&(*buffer)[current_size], "\n", 2); 85 strncpy(&(*buffer)[current_size + 1], &temp_buffer[file_offset], copy_size); 86 strncpy(&(*buffer)[current_size + copy_size], "", 1); 87 // -- Load local "header.h" 88 char *next_quote = strchr(first_hash, '"'); 89 char *next_new_line = strchr(first_hash, '\n'); 90 bool is_local_header = is_hash_include && next_quote 91 && (next_new_line - next_quote > 0); 92 if (is_local_header) { 93 // ---- Build source path 94 char *include_source_path; 95 long root_length = strrchr(source_file_path, '/') - source_file_path; 96 long include_file_name_len = strchr(&next_quote[1], '"') - next_quote - 1; 97 ierr = CeedCalloc(root_length + include_file_name_len + 2, 98 &include_source_path); CeedChk(ierr); 99 strncpy(include_source_path, source_file_path, root_length + 1); 100 strncpy(&include_source_path[root_length + 1], &next_quote[1], 101 include_file_name_len); 102 strncpy(&include_source_path[root_length + include_file_name_len + 1], "", 1); 103 // ---- Recursive call to load source to buffer 104 ierr = CeedLoadSourceToInitalizedBuffer(ceed, include_source_path, buffer); 105 CeedChk(ierr); 106 ierr = CeedFree(&include_source_path); CeedChk(ierr); 107 } 108 file_offset = strchr(first_hash, '\n') - temp_buffer + 1; 109 } 110 // -- Next hash 111 first_hash = strchr(&first_hash[1], '#'); 112 } 113 // Copy rest of source file into buffer 114 long current_size = strlen(*buffer); 115 long copy_size = strlen(&temp_buffer[file_offset]); 116 ierr = CeedRealloc(current_size + copy_size + 2, buffer); CeedChk(ierr); 117 strncpy(&(*buffer)[current_size], "\n", 2); 118 strncpy(&(*buffer)[current_size + 1], &temp_buffer[file_offset], copy_size); 119 strncpy(&(*buffer)[current_size + copy_size + 1], "", 1); 120 121 // Cleanup 122 ierr = CeedFree(&temp_buffer); CeedChk(ierr); 123 124 // Debug 125 CeedDebug256(ceed, 1, "---------- Ceed JiT ----------\n"); 126 CeedDebug256(ceed, 1, "Current source file: "); 127 CeedDebug256(ceed, 255, "%s\n", source_file_path); 128 CeedDebug256(ceed, 1, "Final buffer:\n"); 129 CeedDebug256(ceed, 255, "%s\n", *buffer); 130 131 return CEED_ERROR_SUCCESS; 132 } 133 134 /** 135 @brief Initalize and load source file into string buffer, including full text 136 of local files in place of `#include "local.h"`. 137 Note: Caller is responsible for freeing the string buffer with `CeedFree()`. 138 139 @param ceed A Ceed object for error handling 140 @param[in] source_file_path Absolute path to source file 141 @param[out] buffer String buffer for source file contents 142 143 @return An error code: 0 - success, otherwise - failure 144 145 @ref Backend 146 **/ 147 int CeedLoadSourceToBuffer(Ceed ceed, const char *source_file_path, 148 char **buffer) { 149 int ierr; 150 151 // Initalize buffer 152 ierr = CeedCalloc(1, buffer); CeedChk(ierr); 153 154 // Load to initalized buffer 155 ierr = CeedLoadSourceToInitalizedBuffer(ceed, source_file_path, buffer); 156 CeedChk(ierr); 157 158 return CEED_ERROR_SUCCESS; 159 } 160 161 /** 162 @brief Get root of search path for installed files for JiT 163 164 @param ceed A Ceed object for error handling 165 @param[out] jit_source_root String for search path root 166 167 @return An error code: 0 - success, otherwise - failure 168 169 @ref Backend 170 **/ 171 int CeedGetJitSourceRoot(Ceed ceed, const char **jit_source_root) { 172 CeedDebug256(ceed, 1, "JiT Source Root: "); 173 CeedDebug256(ceed, 255, "%s\n", ceed->jit_source_root); 174 *jit_source_root = ceed->jit_source_root; 175 return CEED_ERROR_SUCCESS; 176 } 177 178 /** 179 @brief Find the relative filepath to an installed JiT file 180 181 @param[in] absolute_file_path Absolute path to installed JiT file 182 @param[out] relative_file_path Relative path to installed JiT file 183 184 @return An error code: 0 - success, otherwise - failure 185 186 @ref Backend 187 **/ 188 int CeedGetJitRelativePath(const char *absolute_file_path, 189 const char **relative_file_path) { 190 *(relative_file_path) = strstr(absolute_file_path, "ceed-jit-source"); 191 192 if (!*relative_file_path) 193 // LCOV_EXCL_START 194 return CeedError(NULL, CEED_ERROR_MAJOR, 195 "Couldn't find relative path including " 196 "'ceed-jit-source' for: %s", absolute_file_path); 197 // LCOV_EXCL_STOP 198 199 return CEED_ERROR_SUCCESS; 200 } 201 202 /** 203 @brief Build an absolute filepath from a base filepath and an absolute filepath. 204 This helps construct source file paths for `CeedLoadSourceToBuffer()`. 205 Note: Caller is responsible for freeing the string buffer with `CeedFree()`. 206 207 @param ceed A Ceed object for error handling 208 @param[in] base_file_path Absolute path to current file 209 @param[in] relative_file_path Relative path to target file 210 @param[out] new_file_path String buffer for absolute path to target file 211 212 @return An error code: 0 - success, otherwise - failure 213 214 @ref Backend 215 **/ 216 int CeedPathConcatenate(Ceed ceed, const char *base_file_path, 217 const char *relative_file_path, char **new_file_path) { 218 int ierr; 219 char *last_slash = strrchr(base_file_path, '/'); 220 size_t base_length = (last_slash - base_file_path + 1), 221 relative_length = strlen(relative_file_path), 222 new_file_path_length = base_length + relative_length + 1; 223 224 ierr = CeedCalloc(new_file_path_length, new_file_path); CeedChk(ierr); 225 memcpy(*new_file_path, base_file_path, base_length); 226 memcpy(&((*new_file_path)[base_length]), relative_file_path, relative_length); 227 228 return CEED_ERROR_SUCCESS; 229 } 230 231 /** 232 @brief Build an absolute filepath to an installed JiT file 233 234 @param ceed A Ceed object for error handling 235 @param[in] relative_file_path Relative path to installed JiT file 236 @param[out] new_file_path String buffer for absolute path to target file 237 238 @return An error code: 0 - success, otherwise - failure 239 240 @ref Backend 241 **/ 242 int CeedGetInstalledJitPath(Ceed ceed, const char *relative_file_path, 243 char **jit_file_path) { 244 int ierr; 245 const char *jit_source_root; 246 247 ierr = CeedGetJitSourceRoot(ceed, &jit_source_root); CeedChk(ierr); 248 249 char *last_slash = strrchr(jit_source_root, '/'); 250 size_t base_length = (last_slash - jit_source_root + 1), 251 relative_length = strlen(relative_file_path), 252 new_file_path_length = base_length + relative_length + 1; 253 254 ierr = CeedCalloc(new_file_path_length, jit_file_path); CeedChk(ierr); 255 memcpy(*jit_file_path, jit_source_root, base_length); 256 memcpy(&((*jit_file_path)[base_length]), relative_file_path, relative_length); 257 258 return CEED_ERROR_SUCCESS; 259 } 260