iota_move/
build.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use std::{fs, path::Path};
6
7use clap::Parser;
8use iota_move_build::{BuildConfig, implicit_deps};
9use iota_package_management::system_package_versions::latest_system_packages;
10use move_cli::base;
11use move_package::BuildConfig as MoveBuildConfig;
12
13use crate::manage_package::resolve_lock_file_path;
14
15const LAYOUTS_DIR: &str = "layouts";
16const STRUCT_LAYOUTS_FILENAME: &str = "struct_layouts.yaml";
17
18/// Build a move package.
19#[derive(Parser)]
20#[group(id = "iota-move-build")]
21pub struct Build {
22    /// Include the contents of packages in dependencies that haven't been
23    /// published (only relevant when dumping bytecode as base64)
24    #[arg(long, global = true)]
25    pub with_unpublished_dependencies: bool,
26    /// Whether we are printing in base64.
27    #[arg(long, global = true)]
28    pub dump_bytecode_as_base64: bool,
29    /// Don't specialize the package to the active chain when dumping bytecode
30    /// as Base64. This allows building to proceed without a network connection
31    /// or active environment, but it will not be able to automatically
32    /// determine the addresses of its dependencies.
33    #[arg(long, global = true, requires = "dump_bytecode_as_base64")]
34    pub ignore_chain: bool,
35    /// If true, generate struct layout schemas for all struct types passed into
36    /// `entry` functions declared by modules in this package These layout
37    /// schemas can be consumed by clients (e.g., the TypeScript SDK) to enable
38    /// serialization/deserialization of transaction arguments and events.
39    #[arg(long, global = true)]
40    pub generate_struct_layouts: bool,
41    /// The chain ID, if resolved. Required when the dump_bytecode_as_base64 is
42    /// true, for automated address management, where package addresses are
43    /// resolved for the respective chain in the Move.lock file.
44    #[arg(skip)]
45    pub chain_id: Option<String>,
46}
47
48impl Build {
49    pub fn execute(
50        &self,
51        path: Option<&Path>,
52        build_config: MoveBuildConfig,
53    ) -> anyhow::Result<()> {
54        let rerooted_path = base::reroot_path(path)?;
55        let build_config = resolve_lock_file_path(build_config, Some(&rerooted_path))?;
56        Self::execute_internal(
57            &rerooted_path,
58            build_config,
59            self.generate_struct_layouts,
60            self.chain_id.clone(),
61        )
62    }
63
64    pub fn execute_internal(
65        rerooted_path: &Path,
66        mut config: MoveBuildConfig,
67        generate_struct_layouts: bool,
68        chain_id: Option<String>,
69    ) -> anyhow::Result<()> {
70        config.implicit_dependencies = implicit_deps(latest_system_packages());
71        let pkg = BuildConfig {
72            config,
73            run_bytecode_verifier: true,
74            print_diags_to_stderr: true,
75            chain_id,
76        }
77        .build(rerooted_path)?;
78
79        if generate_struct_layouts {
80            let layout_str = serde_yaml::to_string(&pkg.generate_struct_layouts()).unwrap();
81            // store under <package_path>/build/<package_name>/layouts/struct_layouts.yaml
82            let dir_name = rerooted_path
83                .join("build")
84                .join(pkg.package.compiled_package_info.package_name.as_str())
85                .join(LAYOUTS_DIR);
86            let layout_filename = dir_name.join(STRUCT_LAYOUTS_FILENAME);
87            fs::create_dir_all(dir_name)?;
88            fs::write(layout_filename, layout_str)?
89        }
90
91        pkg.package
92            .compiled_package_info
93            .build_flags
94            .update_lock_file_toolchain_version(rerooted_path, env!("CARGO_PKG_VERSION").into())?;
95
96        Ok(())
97    }
98}