1- use std:: process:: Command ;
1+ use std:: io:: Write ;
2+ use std:: path:: { Path , PathBuf } ;
3+ use std:: process:: { Command , Output } ;
24use std:: { env, fs} ;
35
46use cached:: proc_macro:: cached;
57use serde:: { Deserialize , Serialize } ;
8+ use tempfile:: NamedTempFile ;
69
710const CAIRO0_PIP_REQUIREMENTS_FILE : & str = "tests/requirements.txt" ;
11+ const LOCAL_CAIRO1_REPO_RELATIVE_PATH : & str = "../../../cairo" ;
812
913/// Objects for simple deserialization of Cargo.toml to fetch the Cairo1 compiler version.
1014/// The compiler itself isn't actually a dependency, so we compile by using the version of the
@@ -52,6 +56,25 @@ pub fn cairo1_compiler_version() -> String {
5256 }
5357}
5458
59+ /// Returns the path to the local Cairo1 compiler repository.
60+ fn local_cairo1_compiler_repo_path ( ) -> PathBuf {
61+ // Location of blockifier's Cargo.toml.
62+ let manifest_dir = env:: var ( "CARGO_MANIFEST_DIR" ) . unwrap ( ) ;
63+
64+ // Returns <blockifier_crate_root>/<RELATIVE_PATH_TO_CAIRO_REPO>.
65+ Path :: new ( & manifest_dir) . join ( LOCAL_CAIRO1_REPO_RELATIVE_PATH )
66+ }
67+
68+ /// Run a command, assert exit code is zero (otherwise panic with stderr output).
69+ fn run_and_verify_output ( command : & mut Command ) -> Output {
70+ let output = command. output ( ) . unwrap ( ) ;
71+ if !output. status . success ( ) {
72+ let stderr_output = String :: from_utf8 ( output. stderr ) . unwrap ( ) ;
73+ panic ! ( "{stderr_output}" ) ;
74+ }
75+ output
76+ }
77+
5578/// Compiles a Cairo0 program using the deprecated compiler.
5679pub fn cairo0_compile ( path : String , extra_arg : Option < String > , debug_info : bool ) -> Vec < u8 > {
5780 verify_cairo0_compiler_deps ( ) ;
@@ -69,8 +92,34 @@ pub fn cairo0_compile(path: String, extra_arg: Option<String>, debug_info: bool)
6992}
7093
7194/// Compiles a Cairo1 program using the compiler version set in the Cargo.toml.
72- pub fn cairo1_compile ( _path : String ) -> Vec < u8 > {
73- todo ! ( ) ;
95+ pub fn cairo1_compile ( path : String , git_tag_override : Option < String > ) -> Vec < u8 > {
96+ verify_cairo1_compiler_deps ( git_tag_override) ;
97+ let cairo1_compiler_path = local_cairo1_compiler_repo_path ( ) ;
98+ let mut cargo_command = Command :: new ( "cargo" ) ;
99+ let sierra_output = run_and_verify_output ( cargo_command. args ( [
100+ "run" ,
101+ & format ! ( "--manifest-path={}/Cargo.toml" , cairo1_compiler_path. to_string_lossy( ) ) ,
102+ "--bin" ,
103+ "starknet-compile" ,
104+ "--" ,
105+ "--single-file" ,
106+ & path,
107+ ] ) ) ;
108+ let mut temp_file = NamedTempFile :: new ( ) . unwrap ( ) ;
109+
110+ temp_file. write_all ( & sierra_output. stdout ) . unwrap ( ) ;
111+ let temp_path_str = temp_file. into_temp_path ( ) ;
112+
113+ let mut cargo_command = Command :: new ( "cargo" ) ;
114+ let casm_output = run_and_verify_output ( cargo_command. args ( [
115+ "run" ,
116+ & format ! ( "--manifest-path={}/Cargo.toml" , cairo1_compiler_path. to_string_lossy( ) ) ,
117+ "--bin" ,
118+ "starknet-sierra-compile" ,
119+ temp_path_str. to_str ( ) . unwrap ( ) ,
120+ ] ) ) ;
121+
122+ casm_output. stdout
74123}
75124
76125/// Verifies that the required dependencies are available before compiling.
@@ -97,3 +146,16 @@ fn verify_cairo0_compiler_deps() {
97146 CAIRO0_PIP_REQUIREMENTS_FILE
98147 ) ;
99148}
149+
150+ fn verify_cairo1_compiler_deps ( git_tag_override : Option < String > ) {
151+ // TODO(Dori, 1/6/2024): Check repo exists.
152+ let tag = git_tag_override. unwrap_or ( format ! ( "v{}" , cairo1_compiler_version( ) ) ) ;
153+ // Checkout the required version in the compiler repo.
154+ run_and_verify_output ( Command :: new ( "git" ) . args ( [
155+ "-C" ,
156+ // TODO(Dori, 1/6/2024): Handle CI case (repo path will be different).
157+ local_cairo1_compiler_repo_path ( ) . to_str ( ) . unwrap ( ) ,
158+ "checkout" ,
159+ & tag,
160+ ] ) ) ;
161+ }
0 commit comments