1 // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at 2 // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights 3 // reserved. See files LICENSE and NOTICE for details. 4 // 5 // This file is part of CEED, a collection of benchmarks, miniapps, software 6 // libraries and APIs for efficient high-order finite element and spectral 7 // element discretizations for exascale applications. For more information and 8 // source code availability see http://github.com/ceed. 9 // 10 // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC, 11 // a collaborative effort of two U.S. Department of Energy organizations (Office 12 // of Science and the National Nuclear Security Administration) responsible for 13 // the planning and preparation of a capable exascale ecosystem, including 14 // software, applications, hardware, advanced system engineering and early 15 // testbed platforms, in support of the nation's exascale computing imperative. 16 17 #include <ceed/ceed.h> 18 #include <ceed/backend.h> 19 #include <ceed/jit-tools.h> 20 #include <stdbool.h> 21 #include <stdio.h> 22 #include <string.h> 23 24 /** 25 @brief Load source file into initalized string buffer, including full text 26 of local files in place of `#include "local.h"` 27 28 @param ceed A Ceed object for error handling 29 @param[in] source_file_path Absolute path to source file 30 @param[out] buffer String buffer for source file contents 31 32 @return An error code: 0 - success, otherwise - failure 33 34 @ref Backend 35 **/ 36 static inline int CeedLoadSourceToInitalizedBuffer(Ceed ceed, 37 const char *source_file_path, char **buffer) { 38 int ierr; 39 FILE *source_file; 40 long file_size, file_offset = 0; 41 char *temp_buffer; 42 43 // Debug 44 CeedDebug256(ceed, 1, "---------- Ceed JiT ----------\n"); 45 CeedDebug256(ceed, 1, "Current source file: "); 46 CeedDebug256(ceed, 255, "%s\n", source_file_path); 47 CeedDebug256(ceed, 1, "Current buffer:\n"); 48 CeedDebug256(ceed, 255, "%s\n", *buffer); 49 50 // Read file to temporary buffer 51 source_file = fopen(source_file_path, "rb"); 52 if (!source_file) 53 // LCOV_EXCL_START 54 return CeedError(ceed, CEED_ERROR_MAJOR, "Couldn't open source file: %s", 55 source_file_path); 56 // LCOV_EXCL_STOP 57 // -- Compute size of source 58 fseek(source_file, 0L, SEEK_END); 59 file_size = ftell(source_file); 60 rewind(source_file); 61 // -- Allocate memory for entire source file 62 ierr = CeedCalloc(file_size + 1, &temp_buffer); CeedChk(ierr); 63 // -- Copy the file into the buffer 64 if (1 != fread(temp_buffer, file_size, 1, source_file)) { 65 // LCOV_EXCL_START 66 fclose(source_file); 67 ierr = CeedFree(&temp_buffer); CeedChk(ierr); 68 return CeedError(ceed, CEED_ERROR_MAJOR, "Couldn't read source file: %s", 69 source_file_path); 70 // LCOV_EXCL_STOP 71 } 72 fclose(source_file); 73 74 // Search for headers to include 75 const char *first_hash = strchr(temp_buffer, '#'); 76 while (first_hash) { 77 // -- Check for 'include' keyword 78 const char *next_e = strchr(first_hash, 'e'); 79 char keyword[8] = ""; 80 if (next_e) 81 strncpy(keyword, &next_e[-6], 7); 82 bool is_hash_include = !strcmp(keyword, "include"); 83 // ---- Spaces allowed in '# include <header.h>' 84 if (next_e) 85 for (CeedInt i = 1; first_hash - next_e + i < -6; i++) 86 is_hash_include &= first_hash[i] == ' '; 87 if (is_hash_include) { 88 // -- Copy into buffer all preceding # 89 long current_size = strlen(*buffer); 90 long copy_size = first_hash - &temp_buffer[file_offset]; 91 ierr = CeedRealloc(current_size + copy_size + 2, buffer); CeedChk(ierr); 92 strncpy(&(*buffer)[current_size], "\n", 2); 93 strncpy(&(*buffer)[current_size + 1], &temp_buffer[file_offset], copy_size); 94 strncpy(&(*buffer)[current_size + copy_size], "", 1); 95 // -- Load local "header.h" 96 char *next_quote = strchr(first_hash, '"'); 97 char *next_new_line = strchr(first_hash, '\n'); 98 bool is_local_header = is_hash_include && next_quote 99 && (next_new_line - next_quote > 0); 100 if (is_local_header) { 101 // ---- Build source path 102 char *include_source_path; 103 long root_length = strrchr(source_file_path, '/') - source_file_path; 104 long include_file_name_len = strchr(&next_quote[1], '"') - next_quote - 1; 105 ierr = CeedCalloc(root_length + include_file_name_len + 2, 106 &include_source_path); CeedChk(ierr); 107 strncpy(include_source_path, source_file_path, root_length + 1); 108 strncpy(&include_source_path[root_length + 1], &next_quote[1], 109 include_file_name_len); 110 strncpy(&include_source_path[root_length + include_file_name_len + 1], "", 1); 111 // ---- Recursive call to load source to buffer 112 ierr = CeedLoadSourceToInitalizedBuffer(ceed, include_source_path, buffer); 113 CeedChk(ierr); 114 ierr = CeedFree(&include_source_path); CeedChk(ierr); 115 } 116 file_offset = strchr(first_hash, '\n') - temp_buffer + 1; 117 } 118 // -- Next hash 119 first_hash = strchr(&first_hash[1], '#'); 120 } 121 // Copy rest of source file into buffer 122 long current_size = strlen(*buffer); 123 long copy_size = strlen(&temp_buffer[file_offset]); 124 ierr = CeedRealloc(current_size + copy_size + 2, buffer); CeedChk(ierr); 125 strncpy(&(*buffer)[current_size], "\n", 2); 126 strncpy(&(*buffer)[current_size + 1], &temp_buffer[file_offset], copy_size); 127 strncpy(&(*buffer)[current_size + copy_size + 1], "", 1); 128 129 // Cleanup 130 ierr = CeedFree(&temp_buffer); CeedChk(ierr); 131 132 // Debug 133 CeedDebug256(ceed, 1, "---------- Ceed JiT ----------\n"); 134 CeedDebug256(ceed, 1, "Current source file: "); 135 CeedDebug256(ceed, 255, "%s\n", source_file_path); 136 CeedDebug256(ceed, 1, "Final buffer:\n"); 137 CeedDebug256(ceed, 255, "%s\n", *buffer); 138 139 return CEED_ERROR_SUCCESS; 140 } 141 142 /** 143 @brief Initalize and load source file into string buffer, including full text 144 of local files in place of `#include "local.h"`. 145 Note: Caller is responsible for freeing the string buffer with `CeedFree()`. 146 147 @param ceed A Ceed object for error handling 148 @param[in] source_file_path Absolute path to source file 149 @param[out] buffer String buffer for source file contents 150 151 @return An error code: 0 - success, otherwise - failure 152 153 @ref Backend 154 **/ 155 int CeedLoadSourceToBuffer(Ceed ceed, const char *source_file_path, 156 char **buffer) { 157 int ierr; 158 159 // Initalize buffer 160 ierr = CeedCalloc(1, buffer); CeedChk(ierr); 161 162 // Load to initalized buffer 163 ierr = CeedLoadSourceToInitalizedBuffer(ceed, source_file_path, buffer); 164 CeedChk(ierr); 165 166 return CEED_ERROR_SUCCESS; 167 } 168