xbuild

repository·master·Indexed 20 days ago

https://github.com/rust-mobile/xbuild

A build tool for Rust projects designed to simplify cross-compiling and publishing native applications to major mobile and desktop stores. It includes a CLI for managing connected devices, diagnosing environment issues via `x doctor`, and a library for creating, signing, and verifying Android APKs, including manifest compilation and resource management.

Tokens
25.9K
Snippets
97
Records
128
Agent score
70%

What's inside xbuild

  1. Data structures in DecisionInfo

    master

    The PRI decision model is composed of the following structures:

    • Decision: Represents a top-level decision, containing a list of indices to QualifierSet objects.
    • QualifierSet: A collection of indices to Qualifier objects.
    • Qualifier: The leaf node containing:
      • qualifier_type: A QualifierType enum.
      • priority: A u16 value.
      • fallback_score: An f32 value.
      • value: A String representing the qualifier's value.
  2. Inheritable values in Cargo manifests

    master

    In xbuild, certain package fields (like version and description) use the Inheritable<T> type. This allows a package to either define its own value or inherit a value from the parent workspace.

    An Inheritable field can be represented in TOML in two ways:

    1. Direct Value: A standard value (e.g., version = "0.1.0").
    2. Inherited: A signal to inherit from the workspace (e.g., version = { workspace = true }).
  3. Understand the Cargo manifest schema in xbuild

    master

    The xbuild manifest parser follows the standard Cargo Cargo.toml structure, supporting both virtual workspaces and individual packages.

    Key Components

    • Workspace: A manifest that defines a collection of packages. It can contain members (paths to package directories) and default_members. A workspace can also define a package section (of type WorkspacePackage) to provide root-level values like version and description.
    • Package: A standard Cargo package definition. It must contain a name. Fields like version and description use the Inheritable pattern.
    • Inheritable Values: Certain fields in a Package can either be a direct value or marked for inheritance from the workspace. This is represented by the Inheritable<T> type.

    Schema Summary

    SectionKeyTypeDescription
    [workspace]membersVec<String>List of paths to workspace members.
    [workspace]default_membersVec<String>List of default workspace members.
    [workspace]packageWorkspacePackageRoot values for the workspace.
    [workspace].packageversionOption<String>Workspace-level version.
    [workspace].packagedescriptionOption<String>Workspace-level description.
    [package]nameStringThe name of the package.
    [package]versionInheritable<String>The package version (can be inherited).
    [package]descriptionOption<Inheritable<String>>The package description (can be inherited).
  4. Platform-specific build requirements and constraints

    master

    When using x build, certain platform-specific constraints apply:

    Android

    • Library Requirement: To build APKs or AABs, your project must contain a src/lib.rs file (it must be a library crate, not just a binary).
    • AAB Limitation: Android App Bundles (AABs) can only be built using the android_gradle configuration. Direct packaging is not supported for AABs.

    macOS

    • Notarization: If a target API key is provided, xbuild will attempt to notarize the AppBundle or the resulting .dmg.
    • DMG Creation: If the target format is Dmg, xbuild will create a disk image and can sign it if a signer is provided.

    iOS

    • Provisioning: You can provide a provisioning profile to be included in the AppBundle.
    • Assets: Supports including Assets.car files via the configuration.

    Windows

    • Supported Formats: Currently supports Exe (simple binary copy) and Msix (packaged application). Other formats are unsupported.
  5. Define asset paths and alignment

    master

    Assets in xbuild can be defined using two formats in the configuration:

    1. Simple Path: A direct string representing the path.
    2. Extended Path: An object providing more control:
      • path: The file path.
      • optional: (Boolean) Whether the asset is optional.
      • alignment: Controls how the file is stored in the zip/package. Options include:
        • Aligned(n): Align the file to n bytes.
        • Unaligned: Do not align.
        • Compressed: Standard compression (default).
    assets:
      - path: "assets/config.json"
      - extended:
          path: "assets/large_data.bin"
          optional: true
          alignment: 4
  6. Use relative paths in Cargo environment variables

    master

    When configuring environment variables in .cargo/config.toml, you can use the relative = true option within an extended object. This tells Cargo to resolve the provided value relative to the directory containing the .cargo/config.toml file.

    This is useful for pointing to local assets, source directories, or toolchains that are part of your workspace structure without hardcoding absolute paths.

    [env]
    # If config.toml is in /project/.cargo/config.toml
    # This will resolve to /project/assets/data.bin
    ASSET_PATH = { value = "../assets/data.bin", relative = true }
  7. Understand PRI file section types via SectionData

    master

    A Section in a PRI file contains metadata (flags, qualifiers) and a payload defined by the SectionData enum. When reading a PRI file, the library automatically identifies the section type based on its 16-byte identifier.

    Supported SectionData variants:

    • DataItem
    • PriDescriptor
    • ResourceMap
    • DecisionInfo
    • HierarchicalSchema
    • Unknown (used when the identifier does not match known types, preserving the raw bytes)

    This allows the library to be extensible; unknown sections are preserved during read/write cycles even if they cannot be parsed into structured types.

  8. Manage build environments with BuildEnv

    master

    The BuildEnv struct is the primary orchestrator for an xbuild session. It encapsulates the Cargo configuration, the BuildTarget requirements, and paths to SDKs and build directories.

    Key Capabilities

    • Path Resolution: Automatically calculates paths for build_dir, cache_dir, output, and executable based on the target.
    • SDK Integration: Provides access to platform-specific SDK paths (e.g., android_sdk(), macos_sdk(), windows_sdk()).
    • Cargo Orchestration: The cargo_build method prepares a CargoBuild instance configured with the correct linker arguments, RPATHs, and SDK paths for the target platform.
    • Artifact Management: Use cargo_artefact to locate the resulting compiled files.
    impl BuildEnv {
        pub fn new(args: BuildArgs) -> Result<Self>;
        pub fn cargo_build(&self, target: CompileTarget, target_dir: &Path) -> Result<CargoBuild>;
        pub fn output(&self) -> PathBuf;
        pub fn executable(&self) -> PathBuf;
    }
  9. Create and build an AppImage

    master

    The AppImage struct provides a programmatic interface to construct an AppImage bundle. The process involves initializing a new AppImage directory, populating it with required files (like .desktop entries, icons, and application binaries), and finally calling build to compress the directory into a squashfs image wrapped with the xbuild runtime.

    Workflow:

    1. Call AppImage::new(build_dir, name) to initialize the .AppDir structure.
    2. Use add_desktop(), add_icon(), and add_file() to populate the bundle.
    3. Call build(out_path, signer) to generate the final executable.

    Requirements:

    • The mksquashfs command must be installed on the host system to perform the compression step.
    use std::path::Path;
    use appimage::AppImage;
    
    fn main() -> anyhow::Result<()> {
        let build_dir = Path::new("./build");
        let app_name = "my-app".to_string();
        let output_path = Path::new("./my-app.AppImage");
    
        // 1. Initialize
        let appimage = AppImage::new(build_dir, app_name.clone())?;
    
        // 2. Populate
        appimage.add_desktop()?;
        appimage.add_icon(Path::new("assets/icon.png"))?;
        appimage.add_file(Path::new("target/release/my-app"), Path::new("my-app"))?;
        appimage.add_apprun()?;
    
        // 3. Build
        appimage.build(output_path, None)?;
    
        Ok(())
    }
  10. Build mobile and desktop applications with `x build`

    master

    The x build command automates the process of compiling Rust code for multiple platforms and packaging them into distributable formats (like APK, AppBundle, AppImage, MSIX, etc.).

    Key behaviors:

    • Artifact Fetching: Automatically fetches precompiled artifacts unless running in --offline mode.
    • Rust Compilation: Invokes cargo to build binaries or libraries (cdylib) for the specified target architectures.
    • Android Special Handling:
      • Android App Bundles (AABs) currently require the android_gradle flag to be set, as they must be built via gradle rather than direct packaging.
      • Android builds require a library (lib.rs must exist) to create APKs or AABs.
      • Automatically collects required shared libraries (including libc++_shared.so if needed) and bundles them into the package.
    • Platform Packaging:
      • Linux: Creates AppImage by adding apprun, desktop files, icons, and the main binary/library.
      • macOS: Creates AppBundle (.app), handles signing, notarization (if an API key is provided), and can create .dmg files.
      • iOS: Creates AppBundle (.app) and packages it into an .ipa file, supporting provisioning profiles and Assets.car.
      • Windows: Supports .exe (copying the binary) and .msix (packaging with manifest and icon).
    • Assets & Icons: Automatically includes icons and assets defined in the project configuration.
  11. Configure Apple signing and provisioning

    master

    For iOS development, you must manage Apple signing certificates and mobile provisioning profiles:

    • Signing Keys/Certificates: Refer to the apple-codesign documentation for management instructions.
    • Provisioning Profiles: There is no cross-platform way to generate these without an Apple Developer account. You must use Xcode or a tool like cook to generate them.