Skip to content
This repository was archived by the owner on Jan 12, 2024. It is now read-only.

Conversation

@idavis
Copy link
Contributor

@idavis idavis commented Nov 19, 2021

(QDK Release: No changes visible to the users)

  • QIR Runtime build is now done through cmake instead of PowerShell configuration.
  • microsoft-quantum-qir-runtime-sys package compiles and sets up embedding/linkage
  • CC/CXX/RC env vars are no longer needed
  • Adds a basic runtime driver for nonadaptive jit execution.

@kuzminrobin
Copy link
Contributor

(Feel free to ignore, I don't know Rust and the background of this effort)

src/Qir/microsoft-quantum-qir-runtime-sys

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".
The name "microsoft-quantum-qir-runtime-sys" seems to me somewhat redundantly long name for a dir, where the part "microsoft-quantum-qir" does not add any info. However if you want to keep the dir name in sync with the package name, then that totally makes sense.

@kuzminrobin
Copy link
Contributor

(Feel free to ignore on the same reasons as in the previous comment)
In the dir "src" there seem to be the files of different purpose.
Some files (or parts of the files) seem to be a part of the build infrastructure,
some files (or parts) seem to be a regular source code,
and some parts seem to be the tests.
Placing the regular source code and the tests for it in the same file (and the same dir) may be a common practice in Rust (I don't know), but as for the files that are a part of the build infra, I would consider separating/moving them to a different dir from sources and tests.

Comment on lines +16 to +22
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)?;
}
Copy link
Contributor

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):

Suggested change
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)?;

Comment on lines +27 to +41
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(())
}
Copy link
Contributor

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?

Copy link
Contributor

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.

Comment on lines +46 to +70
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")
}
Copy link
Contributor

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)

Suggested change
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);
}

Comment on lines +8 to +24
#[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"
));
Copy link
Contributor

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"
));

Copy link
Contributor

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.

@cgranade
Copy link
Contributor

(Feel free to ignore, I don't know Rust and the background of this effort)

src/Qir/microsoft-quantum-qir-runtime-sys

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". The name "microsoft-quantum-qir-runtime-sys" seems to me somewhat redundantly long name for a dir, where the part "microsoft-quantum-qir" does not add any info. However if you want to keep the dir name in sync with the package name, then that totally makes sense.

The suffix -sys in crate names is somewhat of a Rust idiom, and carries with it the meaning that the crate acts to wrap a non-Rust library in a Rust package.

@swernli swernli assigned swernli and cgranade and unassigned cgranade and swernli Nov 22, 2021
@idavis idavis merged commit f4f2812 into main Nov 22, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants