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 CeedDebug256(ceed, 2, "JiT Including: %s\n", include_source_path); 106 CeedChk(ierr); 107 ierr = CeedFree(&include_source_path); CeedChk(ierr); 108 } 109 file_offset = strchr(first_hash, '\n') - temp_buffer + 1; 110 } 111 // -- Next hash 112 first_hash = strchr(&first_hash[1], '#'); 113 } 114 // Copy rest of source file into buffer 115 long current_size = strlen(*buffer); 116 long copy_size = strlen(&temp_buffer[file_offset]); 117 ierr = CeedRealloc(current_size + copy_size + 2, buffer); CeedChk(ierr); 118 strncpy(&(*buffer)[current_size], "\n", 2); 119 strncpy(&(*buffer)[current_size + 1], &temp_buffer[file_offset], copy_size); 120 strncpy(&(*buffer)[current_size + copy_size + 1], "", 1); 121 122 // Cleanup 123 ierr = CeedFree(&temp_buffer); CeedChk(ierr); 124 125 // Debug 126 CeedDebug256(ceed, 1, "---------- Ceed JiT ----------\n"); 127 CeedDebug256(ceed, 1, "Current source file: "); 128 CeedDebug256(ceed, 255, "%s\n", source_file_path); 129 CeedDebug256(ceed, 1, "Final buffer:\n"); 130 CeedDebug256(ceed, 255, "%s\n", *buffer); 131 132 return CEED_ERROR_SUCCESS; 133 } 134 135 /** 136 @brief Initalize and load source file into string buffer, including full text 137 of local files in place of `#include "local.h"`. 138 Note: Caller is responsible for freeing the string buffer with `CeedFree()`. 139 140 @param ceed A Ceed object for error handling 141 @param[in] source_file_path Absolute path to source file 142 @param[out] buffer String buffer for source file contents 143 144 @return An error code: 0 - success, otherwise - failure 145 146 @ref Backend 147 **/ 148 int CeedLoadSourceToBuffer(Ceed ceed, const char *source_file_path, 149 char **buffer) { 150 int ierr; 151 152 // Initalize buffer 153 ierr = CeedCalloc(1, buffer); CeedChk(ierr); 154 155 // Load to initalized buffer 156 ierr = CeedLoadSourceToInitalizedBuffer(ceed, source_file_path, buffer); 157 CeedChk(ierr); 158 159 return CEED_ERROR_SUCCESS; 160 } 161 162 /** 163 @brief Get root of search path for installed files for JiT 164 165 @param ceed A Ceed object for error handling 166 @param[out] jit_source_root String for search path root 167 168 @return An error code: 0 - success, otherwise - failure 169 170 @ref Backend 171 **/ 172 int CeedGetJitSourceRoot(Ceed ceed, const char **jit_source_root) { 173 CeedDebug256(ceed, 1, "JiT Source Root: "); 174 CeedDebug256(ceed, 255, "%s\n", ceed->jit_source_root); 175 *jit_source_root = ceed->jit_source_root; 176 return CEED_ERROR_SUCCESS; 177 } 178 179 /** 180 @brief Find the relative filepath to an installed JiT file 181 182 @param[in] absolute_file_path Absolute path to installed JiT file 183 @param[out] relative_file_path Relative path to installed JiT file 184 185 @return An error code: 0 - success, otherwise - failure 186 187 @ref Backend 188 **/ 189 int CeedGetJitRelativePath(const char *absolute_file_path, 190 const char **relative_file_path) { 191 *(relative_file_path) = strstr(absolute_file_path, "ceed/jit-source"); 192 193 if (!*relative_file_path) 194 // LCOV_EXCL_START 195 return CeedError(NULL, CEED_ERROR_MAJOR, 196 "Couldn't find relative path including " 197 "'ceed/jit-source' for: %s", absolute_file_path); 198 // LCOV_EXCL_STOP 199 200 return CEED_ERROR_SUCCESS; 201 } 202 203 /** 204 @brief Build an absolute filepath from a base filepath and an absolute filepath. 205 This helps construct source file paths for `CeedLoadSourceToBuffer()`. 206 Note: Caller is responsible for freeing the string buffer with `CeedFree()`. 207 208 @param ceed A Ceed object for error handling 209 @param[in] base_file_path Absolute path to current file 210 @param[in] relative_file_path Relative path to target file 211 @param[out] new_file_path String buffer for absolute path to target file 212 213 @return An error code: 0 - success, otherwise - failure 214 215 @ref Backend 216 **/ 217 int CeedPathConcatenate(Ceed ceed, const char *base_file_path, 218 const char *relative_file_path, char **new_file_path) { 219 int ierr; 220 char *last_slash = strrchr(base_file_path, '/'); 221 size_t base_length = (last_slash - base_file_path + 1), 222 relative_length = strlen(relative_file_path), 223 new_file_path_length = base_length + relative_length + 1; 224 225 ierr = CeedCalloc(new_file_path_length, new_file_path); CeedChk(ierr); 226 memcpy(*new_file_path, base_file_path, base_length); 227 memcpy(&((*new_file_path)[base_length]), relative_file_path, relative_length); 228 229 return CEED_ERROR_SUCCESS; 230 } 231 232 /** 233 @brief Build an absolute filepath to an installed JiT file 234 235 @param ceed A Ceed object for error handling 236 @param[in] relative_file_path Relative path to installed JiT file 237 @param[out] new_file_path String buffer for absolute path to target file 238 239 @return An error code: 0 - success, otherwise - failure 240 241 @ref Backend 242 **/ 243 int CeedGetInstalledJitPath(Ceed ceed, const char *relative_file_path, 244 char **jit_file_path) { 245 int ierr; 246 const char *jit_source_root; 247 248 ierr = CeedGetJitSourceRoot(ceed, &jit_source_root); CeedChk(ierr); 249 250 char *last_slash = strrchr(jit_source_root, '/'); 251 size_t base_length = (last_slash - jit_source_root + 1), 252 relative_length = strlen(relative_file_path), 253 new_file_path_length = base_length + relative_length + 1; 254 255 ierr = CeedCalloc(new_file_path_length, jit_file_path); CeedChk(ierr); 256 memcpy(*jit_file_path, jit_source_root, base_length); 257 memcpy(&((*jit_file_path)[base_length]), relative_file_path, relative_length); 258 259 return CEED_ERROR_SUCCESS; 260 } 261