Building Gram for Linux

Repository

Clone the Gram repository.

Dependencies

  • Install rustup

  • Install the necessary system libraries:

    script/linux
    

    If you prefer to install the system libraries manually, you can find the list of required packages in the script/linux file.

Linkers {#linker}

On Linux, Rust's default linker is LLVM's lld. Alternative linkers, especially Wild and Mold can significantly improve clean and incremental build time.

For local development Wild is recommended because it's 5-20% faster than Mold.

These linkers can be installed with script/install-mold and script/install-wild.

To use Wild as your default, add these lines to your ~/.cargo/config.toml:

[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=--ld-path=wild"]

[target.aarch64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=--ld-path=wild"]

To use Mold as your default:

[target.'cfg(target_os = "linux")']
rustflags = ["-C", "link-arg=-fuse-ld=mold"]

Building from source

Once the dependencies are installed, you can build using Cargo.

For a debug build of the editor:

cargo run

To run the tests:

cargo test --workspace

In release mode, the primary user interface is the cli crate. You can run it in development with:

cargo run -p cli

Installing a development build

You can install a local build on your machine with:

./script/install-linux

This will build gram and the cli in release mode and make them available at ~/.local/bin/gram, installing .desktop files to ~/.local/share.

Note: If you encounter linker errors similar to the following:

error: linking with `cc` failed: exit status: 1 ...
= note: /usr/bin/ld: /tmp/rustcISMaod/libaws_lc_sys-79f08eb6d32e546e.rlib(f8e4fd781484bd36-bcm.o): in function `aws_lc_0_25_0_handle_cpu_env':
          /aws-lc/crypto/fipsmodule/cpucap/cpu_intel.c:(.text.aws_lc_0_25_0_handle_cpu_env+0x63): undefined reference to `__isoc23_sscanf'
          /usr/bin/ld: /tmp/rustcISMaod/libaws_lc_sys-79f08eb6d32e546e.rlib(f8e4fd781484bd36-bcm.o): in function `pkey_rsa_ctrl_str':
          /aws-lc/crypto/fipsmodule/evp/p_rsa.c:741:(.text.pkey_rsa_ctrl_str+0x20d): undefined reference to `__isoc23_strtol'
          /usr/bin/ld: /aws-lc/crypto/fipsmodule/evp/p_rsa.c:752:(.text.pkey_rsa_ctrl_str+0x258): undefined reference to `__isoc23_strtol'
          collect2: error: ld returned 1 exit status
  = note: some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
  = note: use the `-l` flag to specify native libraries to link
  = note: use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#rustc-link-lib)
error: could not compile `remote_server` (bin "remote_server") due to 1 previous error

Cause: this is caused by known bugs in aws-lc-rs(doesn't support GCC >= 14): FIPS fails to build with GCC >= 14 & GCC-14 - build failure for FIPS module

You can refer to linux: Linker error for remote_server when using script/install-linux for more information.

Workarounds: Set the remote server target to x86_64-unknown-linux-gnu like so export REMOTE_SERVER_TARGET=x86_64-unknown-linux-gnu; script/install-linux

Wayland & X11

Gram supports both X11 and Wayland. By default, we pick whichever we can find at runtime. If you're on Wayland and want to run in X11 mode, use the environment variable WAYLAND_DISPLAY=''.

Packaging Gram

Gram has two main binaries:

  • You will need to build crates/cli and make its binary available in $PATH with the name gram.
  • You will need to build crates/gram and put it at $PATH/to/cli/../../libexec/gram-editor. For example, if you are going to put the cli at ~/.local/bin/gram put gram at ~/.local/libexec/gram-editor. As some linux distributions (notably Arch) discourage the use of libexec, you can also put this binary at $PATH/to/cli/../../lib/gram/gram-editor (e.g. ~/.local/lib/gram/gram-editor) instead.
  • If you are going to provide a .desktop file you can find a template in crates/gram/resources/gram.desktop.in, and use envsubst to populate it with the values required. This file should also be renamed to $APP_ID.desktop so that the file follows the FreeDesktop standards. You should also make this desktop file executable (chmod 755).
  • You will need to ensure that the necessary libraries are installed. You can get the current list by inspecting the built binary on your system.
  • For an example of a complete build script, see script/bundle-linux.
  • You can provide instructions for users who try to update Gram manually by building (or running) Gram with the environment variable GRAM_UPDATE_EXPLANATION. For example: GRAM_UPDATE_EXPLANATION="Please use flatpak to update gram.".
  • Make sure to update the contents of the crates/gram/RELEASE_CHANNEL file to 'stable' with no newline. This will cause Gram to use the credentials manager to remember a user's login.

Other things to note

Zed comes with some (in our opinion) pretty severe caveats:

  • It automatically downloads and installs binaries without explicit user prompting in the same way as rustup/rbenv/pyenv, etc. They say that they "understand this is contentious", and yet they insist on doing it. See here.
  • They download and install extension binaries from zed-industries/extensions without explicit permission or any way to inspect what is being installed. These extensions may in turn install further software without explicit permission or control. For more details, see here.
  • It does not play nice with sandboxes, see here

Our (Gram's) intention is to resolve all of these problems.

Flatpak

Gram's current Flatpak integration exits the sandbox on startup. Workflows that rely on Flatpak's sandboxing may not work as expected.

To build & install the Flatpak package locally follow the steps below:

  1. Install Flatpak for your distribution as outlined here.
  2. Run the script/flatpak/deps script to install the required dependencies.
  3. Run script/flatpak/bundle-flatpak.
  4. Now the package has been installed and has a bundle available at target/release/{app-id}.flatpak.

Memory profiling

heaptrack is quite useful for diagnosing memory leaks. To install it:

$ sudo apt install heaptrack heaptrack-gui
$ cargo install cargo-heaptrack

Then, to build and run Gram with the profiler attached:

$ cargo heaptrack -b gram

When this editor instance is exited, terminal output will include a command to run heaptrack_interpret to convert the *.raw.zst profile to a *.zst file which can be passed to heaptrack_gui for viewing.

Perf recording

This section describes how to generate a flamegraph with resolved symbols from a running editor instance. This can be used to debug when the editor is using a lot of CPU. It's not useful for debugging hangs or memory usage.

During the incident

  • Find the PID (process ID) using: ps -eo size,pid,comm | grep gram | sort | head -n 1 | cut -d ' ' -f 2 Or find the pid of the command gram-editor with the most ram usage in something like htop/btop/top.

  • Install perf: On Ubuntu (derivatives) run sudo apt install linux-tools.

  • Perf Record: run sudo perf record -p <pid you just found>, wait a few seconds to gather data then press Ctrl+C. You should now have a perf.data file

  • Make the output file user owned: run sudo chown $USER:$USER perf.data

  • Get build info: Run gram again and type gram: about in the command pallet to get the exact commit.

Later

  • Build Gram with symbols:

    • Check out the commit found previously and modify Cargo.toml.
    • Apply the following diff, then make a release build.
    [profile.release]
    -debug = "limited"
    +debug = "full"
    
  • Add the symbols to perf database: pref buildid-cache -v -a <path to release gram binary>

  • Resolve the symbols from the db: perf inject -i perf.data -o perf_with_symbols.data

  • Install flamegraph: cargo install cargo-flamegraph

  • Render the flamegraph: flamegraph --perfdata perf_with_symbols.data

Troubleshooting

Cargo errors claiming that a dependency is using unstable features

Try cargo clean and cargo build.