-
Notifications
You must be signed in to change notification settings - Fork 90
Create Rust QIR Runtime Wrapper Library #878
Conversation
* Moving QIR runtime build config into qir_cmake_include CMakeLists.
|
(Feel free to ignore, I don't know Rust and the background of this effort)
The "sys" part seems to me not very informative (does not tell me the purpose or the structure/contents). I would consider a more informative name instead of "sys". |
|
(Feel free to ignore on the same reasons as in the previous comment) |
| if cfg!(target_os = "windows") { | ||
| let path_to_runtime_src = "..\\Runtime"; | ||
| compile_runtime_libraries(path_to_runtime_src)?; | ||
| } else { | ||
| let path_to_runtime_src = "../Runtime"; | ||
| compile_runtime_libraries(path_to_runtime_src)?; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Nit)
Consider deduplicating as much as possible, such that only the differing part is placed in if .. else ... Something like this (pseudocode):
| if cfg!(target_os = "windows") { | |
| let path_to_runtime_src = "..\\Runtime"; | |
| compile_runtime_libraries(path_to_runtime_src)?; | |
| } else { | |
| let path_to_runtime_src = "../Runtime"; | |
| compile_runtime_libraries(path_to_runtime_src)?; | |
| } | |
| let path_separator = (cfg!(target_os = "windows") ? "\\" : "/"); // Either \ or / | |
| let path_to_runtime_src = ".." + path_separator + "Runtime"; // "..\Runtime" or "../Runtime" | |
| compile_runtime_libraries(path_to_runtime_src)?; |
| fn compile_runtime_libraries(path_to_runtime_src: &str) -> Result<(), Box<dyn Error>> { | ||
| let mut config = Config::new(path_to_runtime_src); | ||
|
|
||
| if cfg!(target_os = "windows") { | ||
| config.static_crt(true); | ||
| } | ||
|
|
||
| set_compiler(&mut config)?; | ||
| set_profile(&mut config)?; | ||
|
|
||
| config.generator("Ninja"); | ||
|
|
||
| let _ = config.build(); | ||
| Ok(()) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Nit. I don't know Rust. Talking in C/C++ terminology)
I have an impression that the function always returns Ok(()). If true, then doesn't it make sense to return void?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In Rust, expressions and functions always must return a value (by contrast with void, which is the absence of any value). Typically, a function with no meaningful return value will be marked as returning () (similar to Q#'s Unit or F#'s unit). Here, the return type is Result<(), Box<dyn Error>>, meaning it can either be Ok(()) or Err(t) for some t of type Box<dyn Error>.
All that leads up to that Ok(()) is the Rust equivalent to a void return type in C++.
As for why it seems like it always returns Ok(()), the ? operator at lines 34 and 35 cause early returns when either value is an Error. That's somewhat similar to exceptions, but has the benefit of being much more strongly typed, as it's not possible for a caller to ignore exceptions and as there's no use of exceptional control flow needed.
| if cfg!(target_os = "linux") { | ||
| let mut c_cfg = cc::Build::new(); | ||
| let clang_11 = which::which("clang-11")?; | ||
| c_cfg.compiler(clang_11); | ||
| config.init_c_cfg(c_cfg); | ||
|
|
||
| let mut cxx_cfg = cc::Build::new(); | ||
| let clangpp_11 = which::which("clang++-11")?; | ||
| cxx_cfg.compiler(clangpp_11); | ||
| config.init_cxx_cfg(cxx_cfg); | ||
| } else if cfg!(target_os = "windows") { | ||
| let mut c_cfg = cc::Build::new(); | ||
| let clang = which::which("clang.exe")?; | ||
| c_cfg.compiler(clang); | ||
| config.init_c_cfg(c_cfg); | ||
|
|
||
| let mut cxx_cfg = cc::Build::new(); | ||
| let clangpp = which::which("clang++.exe")?; | ||
| cxx_cfg.compiler(clangpp); | ||
| config.init_cxx_cfg(cxx_cfg); | ||
| } else if cfg!(target_os = "macos") { | ||
| // Use macos default | ||
| } else { | ||
| panic!("Unsupported platform") | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Nit. . . .)
Consider dedulplicating (such that only the difference is in if .. else..), something like (Rust/C/C++ pseudocode)
| if cfg!(target_os = "linux") { | |
| let mut c_cfg = cc::Build::new(); | |
| let clang_11 = which::which("clang-11")?; | |
| c_cfg.compiler(clang_11); | |
| config.init_c_cfg(c_cfg); | |
| let mut cxx_cfg = cc::Build::new(); | |
| let clangpp_11 = which::which("clang++-11")?; | |
| cxx_cfg.compiler(clangpp_11); | |
| config.init_cxx_cfg(cxx_cfg); | |
| } else if cfg!(target_os = "windows") { | |
| let mut c_cfg = cc::Build::new(); | |
| let clang = which::which("clang.exe")?; | |
| c_cfg.compiler(clang); | |
| config.init_c_cfg(c_cfg); | |
| let mut cxx_cfg = cc::Build::new(); | |
| let clangpp = which::which("clang++.exe")?; | |
| cxx_cfg.compiler(clangpp); | |
| config.init_cxx_cfg(cxx_cfg); | |
| } else if cfg!(target_os = "macos") { | |
| // Use macos default | |
| } else { | |
| panic!("Unsupported platform") | |
| } | |
| if cfg!(target_os != "macos") { | |
| if cfg!(target_os != "linux") && cfg!(target_os != "windows"){ | |
| panic!("Unsupported platform") | |
| } | |
| let clang = which::which( | |
| cfg!(target_os = "linux") ? "clang-11" : "clang.exe")?; | |
| let mut c_cfg = cc::Build::new(); | |
| c_cfg.compiler(clang); | |
| config.init_c_cfg(c_cfg); | |
| let clangpp = which::which( | |
| cfg!(target_os = "linux") ? "clang++-11" : "clang++.exe")?; | |
| let mut cxx_cfg = cc::Build::new(); | |
| cxx_cfg.compiler(clangpp); | |
| config.init_cxx_cfg(cxx_cfg); | |
| } |
| #[cfg(target_os = "linux")] | ||
| const FOUNDATION_BYTES: &'static [u8] = include_bytes!(concat!( | ||
| env!("OUT_DIR"), | ||
| "/build/lib/QSharpFoundation/libMicrosoft.Quantum.Qir.QSharp.Foundation.so" | ||
| )); | ||
|
|
||
| #[cfg(target_os = "macos")] | ||
| const FOUNDATION_BYTES: &'static [u8] = include_bytes!(concat!( | ||
| env!("OUT_DIR"), | ||
| "/build/lib/QSharpFoundation/libMicrosoft.Quantum.Qir.QSharp.Foundation.dylib" | ||
| )); | ||
|
|
||
| #[cfg(target_os = "windows")] | ||
| const FOUNDATION_BYTES: &'static [u8] = include_bytes!(concat!( | ||
| env!("OUT_DIR"), | ||
| "/build/lib/QSharpFoundation/Microsoft.Quantum.Qir.QSharp.Foundation.dll" | ||
| )); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just FYI (I'm not saying whether it is good or bad):
I have seen a case where a single name for the dynamic library (written in Rust?) is used for all 3 platforms (in C#). See here, here, and here. Written by Chris.
If that is not applicable to Rust then is it possible to write like this? (deduplicated)
const FOUNDATION_BYTES: &'static [u8] = include_bytes!(concat!(
env!("OUT_DIR"),
#[cfg(target_os = "linux")]
"/build/lib/QSharpFoundation/libMicrosoft.Quantum.Qir.QSharp.Foundation.so"
#[cfg(target_os = "macos")]
"/build/lib/QSharpFoundation/libMicrosoft.Quantum.Qir.QSharp.Foundation.dylib"
#[cfg(target_os = "windows")]
"/build/lib/QSharpFoundation/Microsoft.Quantum.Qir.QSharp.Foundation.dll"
));There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To clarify, I did that due to requirements in our CI and packaging pipeline for .NET projects; I wouldn't recommend following my approach in this case.
The suffix |
(QDK Release: No changes visible to the users)