1414#include < dirent.h>
1515#include < nvrtc.h>
1616#include < stdarg.h>
17+ #include < stdio.h>
1718#include < string.h>
1819#include < sys/stat.h>
1920#include < sys/types.h>
4445// Call system command and capture stdout + stderr
4546// ------------------------------------------------------------------------------
4647static int CeedCallSystem_Core (Ceed ceed, const char *command, const char *message) {
47- CeedDebug (ceed, " Running command:\n $ %s\n " , command);
48+ CeedDebug (ceed, " Running command:\n $ %s" , command);
4849 FILE *output_stream = popen ((command + std::string (" 2>&1" )).c_str (), " r" );
4950
50- CeedCheck (output_stream != nullptr , ceed, CEED_ERROR_BACKEND, " Failed to %s with command: %s" , message, command);
51+ CeedCheck (output_stream != nullptr , ceed, CEED_ERROR_BACKEND, " Failed to %s\n command: \n $ %s" , message, command);
5152
52- char output[4 * CEED_MAX_RESOURCE_LEN];
53+ char line[CEED_MAX_RESOURCE_LEN] = " " ;
54+ std::string output = " " ;
5355
54- while (fgets (output, sizeof (output), output_stream) != nullptr ) {
56+ while (fgets (line, sizeof (line), output_stream) != nullptr ) {
57+ output += line;
5558 }
56- CeedDebug (ceed, " Command output:\n %s\n " , output);
57-
58- CeedCheck (pclose (output_stream) == 0 , ceed, CEED_ERROR_BACKEND, " Failed to %s with command: %s\n and error: %s" , message, command, output);
59+ CeedDebug (ceed, " output:\n %s\n " , output.c_str ());
60+ CeedCheck (pclose (output_stream) == 0 , ceed, CEED_ERROR_BACKEND, " Failed to %s\n command:\n $ %s\n error:\n %s" , message, command, output.c_str ());
5961 return CEED_ERROR_SUCCESS;
6062}
6163
@@ -280,31 +282,67 @@ static int CeedCompileCore_Cuda(Ceed ceed, const char *source, const bool throw_
280282 CeedCallSystem (ceed, command.c_str (), " build Rust crate" );
281283 }
282284
285+ // Get Clang version
286+ bool use_llvm_version = ceed_data->use_llvm_version ;
287+ int llvm_version = ceed_data->llvm_version ;
288+
289+ if (llvm_version == 0 ) {
290+ command = " $(find $(rustup run " + std::string (rust_toolchain) + " rustc --print sysroot) -name llvm-link) --version" ;
291+ CeedDebug (ceed, " Attempting to detect Rust LLVM version.\n command:\n $ %s" , command.c_str ());
292+ FILE *output_stream = popen ((command + std::string (" 2>&1" )).c_str (), " r" );
293+
294+ CeedCheck (output_stream != nullptr , ceed, CEED_ERROR_BACKEND, " Failed to detect Rust LLVM version" );
295+
296+ char line[CEED_MAX_RESOURCE_LEN] = " " ;
297+ std::string output = " " ;
298+
299+ while (fgets (line, sizeof (line), output_stream) != nullptr ) {
300+ output += line;
301+ }
302+ CeedDebug (ceed, " output:\n %s" , output.c_str ());
303+ CeedCheck (pclose (output_stream) == 0 , ceed, CEED_ERROR_BACKEND, " Failed to detect Rust LLVM version\n command:\n $ %s\n error:\n %s" ,
304+ command.c_str (), output.c_str ());
305+
306+ const char *version_substring = strstr (output.c_str (), " LLVM version " );
307+
308+ version_substring += 13 ;
309+
310+ char *next_dot = strchr ((char *)version_substring, ' .' );
311+
312+ next_dot[0 ] = ' \0 ' ;
313+ ceed_data->llvm_version = llvm_version = std::stoi (version_substring);
314+ CeedDebug (ceed, " Rust LLVM version number: %d\n " , llvm_version);
315+
316+ command = std::string (" clang++-" ) + std::to_string (llvm_version);
317+ output_stream = popen ((command + std::string (" 2>&1" )).c_str (), " r" );
318+ ceed_data->use_llvm_version = use_llvm_version = pclose (output_stream) == 0 ;
319+ }
320+
283321 // Compile wrapper kernel
284- command = " clang++ -flto=thin --cuda-gpu-arch=sm_ " + std::to_string (prop. major ) + std::to_string (prop. minor ) +
285- " --cuda-device-only -emit-llvm -S temp/kernel_" + std::to_string (build_id) + " _0_source.cu -o temp/kernel_ " +
286- std::to_string (build_id) + " _1_wrapped.ll " ;
322+ command = " clang++" + (use_llvm_version ? ( std::string ( " - " ) + std::to_string (llvm_version)) : " " ) + " -flto=thin --cuda-gpu-arch=sm_ " +
323+ std::to_string (prop. major ) + std::to_string (prop. minor ) + " --cuda-device-only -emit-llvm -S temp/kernel_" + std::to_string (build_id) +
324+ " _0_source.cu -o temp/kernel_ " + std::to_string (build_id) + " _1_wrapped.ll " ;
287325 command += opts[4 ];
288326 CeedCallSystem (ceed, command.c_str (), " JiT kernel source" );
289327 CeedCallSystem (ceed, (" chmod 0777 temp/kernel_" + std::to_string (build_id) + " _1_wrapped.ll" ).c_str (), " update JiT file permissions" );
290328
291- // the find command finds the rust-installed llvm-link tool and runs it
329+ // Find Rust's llvm-link tool and runs it
292330 command = " $(find $(rustup run " + std::string (rust_toolchain) + " rustc --print sysroot) -name llvm-link) temp/kernel_" +
293331 std::to_string (build_id) +
294332 " _1_wrapped.ll --ignore-non-bitcode --internalize --only-needed -S -o "
295333 " temp/kernel_" +
296334 std::to_string (build_id) + " _2_linked.ll " ;
297335
298336 // Searches for .a files in rust directoy
299- // Note: this is necessary because rust crate names may not match the folder they are in
337+ // Note: this is necessary because Rust crate names may not match the folder they are in
300338 for (CeedInt i = 0 ; i < num_rust_source_dirs; i++) {
301339 std::string dir = rust_dirs[i] + " /target/nvptx64-nvidia-cuda/release" ;
302340 DIR *dp = opendir (dir.c_str ());
303341
304342 CeedCheck (dp != nullptr , ceed, CEED_ERROR_BACKEND, " Could not open directory: %s" , dir.c_str ());
305343 struct dirent *entry;
306344
307- // finds files ending in .a
345+ // Find files ending in .a
308346 while ((entry = readdir (dp)) != nullptr ) {
309347 std::string filename (entry->d_name );
310348
@@ -317,7 +355,6 @@ static int CeedCompileCore_Cuda(Ceed ceed, const char *source, const bool throw_
317355 }
318356
319357 // Link, optimize, and compile final CUDA kernel
320- // note that the find command is used to find the rust-installed llvm tool
321358 CeedCallSystem (ceed, command.c_str (), " link C and Rust source" );
322359 CeedCallSystem (
323360 ceed,
0 commit comments