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