mirror of
https://github.com/tauri-apps/tauri-docs.git
synced 2026-01-31 00:35:16 +01:00
214 lines
6.7 KiB
Plaintext
214 lines
6.7 KiB
Plaintext
---
|
||
title: Embedding External Binaries
|
||
sidebar:
|
||
order: 1
|
||
badge:
|
||
text: WIP
|
||
variant: caution
|
||
---
|
||
|
||
You may need to embed external binaries to add additional functionality to your application or prevent users from installing additional dependencies (e.g., Node.js or Python). We call this binary a `sidecar`.
|
||
|
||
Binaries are executables written in any programming language. Common use cases are Python CLI applications or API servers bundled using `pyinstaller`.
|
||
|
||
To bundle the binaries of your choice, you can add the `externalBin` property to the `tauri > bundle` object in your `tauri.conf.json`. `externalBin` expects a list of strings targeting binaries either with absolute or relative paths.
|
||
|
||
Here is a sample to illustrate the configuration. This is not a complete `tauri.conf.json` file:
|
||
|
||
```json title="src-tauri/tauri.conf.json"
|
||
{
|
||
"tauri": {
|
||
"bundle": {
|
||
"externalBin": [
|
||
"/absolute/path/to/sidecar",
|
||
"relative/path/to/binary",
|
||
"binaries/my-sidecar"
|
||
]
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
:::note
|
||
|
||
The relative paths are relative to the `tauri.conf.json` file which is in the `src-tauri` directory. So `binaries/my-sidecar` would represent `<PROJECT ROOT>/src-tauri/binaries/my-sidecar`.
|
||
|
||
:::
|
||
|
||
To make the external binary work on each supported architecture, a binary with the same name and a `-$TARGET_TRIPLE` suffix must exist on the specified path. For instance, `"externalBin": ["binaries/my-sidecar"]` requires a `src-tauri/binaries/my-sidecar-x86_64-unknown-linux-gnu` executable on Linux or `src-tauri/binaries/my-sidecar-aarch64-apple-darwin` on Mac OS with Apple Silicon.
|
||
|
||
You can find your **current** platform's `-$TARGET_TRIPLE` suffix by looking at the `host:` property reported by the `rustc -Vv` command.
|
||
|
||
If the `grep` and `cut` commands are available, as they should on most Unix systems, you can extract the target triple directly with the following command:
|
||
|
||
```shell
|
||
rustc -Vv | grep host | cut -f2 -d' '
|
||
```
|
||
|
||
On Windows you can use PowerShell instead:
|
||
|
||
```powershell
|
||
rustc -Vv | Select-String "host:" | ForEach-Object {$_.Line.split(" ")[1]}
|
||
```
|
||
|
||
Here's a Node.js script to append the target triple to a binary:
|
||
|
||
```javascript
|
||
const execa = require('execa');
|
||
const fs = require('fs');
|
||
|
||
let extension = '';
|
||
if (process.platform === 'win32') {
|
||
extension = '.exe';
|
||
}
|
||
|
||
async function main() {
|
||
const rustInfo = (await execa('rustc', ['-vV'])).stdout;
|
||
const targetTriple = /host: (\S+)/g.exec(rustInfo)[1];
|
||
if (!targetTriple) {
|
||
console.error('Failed to determine platform target triple');
|
||
}
|
||
fs.renameSync(
|
||
`src-tauri/binaries/sidecar${extension}`,
|
||
`src-tauri/binaries/sidecar-${targetTriple}${extension}`
|
||
);
|
||
}
|
||
|
||
main().catch((e) => {
|
||
throw e;
|
||
});
|
||
```
|
||
|
||
## Running it from Rust
|
||
|
||
On the Rust side, import the `tauri_plugin_shell::ShellExt` trait and call the `shell().sidecar()` function on the AppHandle:
|
||
|
||
```rust
|
||
use tauri_plugin_shell::ShellExt;
|
||
use tauri_plugin_shell::process::CommandEvent;
|
||
|
||
// `sidecar()` expects just the filename, NOT the whole path like in JavaScript
|
||
let sidecar_command = app.shell().sidecar("my-sidecar").unwrap();
|
||
let (mut rx, mut _child) = sidecar_command
|
||
.spawn()
|
||
.expect("Failed to spawn sidecar");
|
||
|
||
tauri::async_runtime::spawn(async move {
|
||
// read events such as stdout
|
||
while let Some(event) = rx.recv().await {
|
||
if let CommandEvent::Stdout(line) = event {
|
||
window
|
||
.emit("message", Some(format!("'{}'", line)))
|
||
.expect("failed to emit event");
|
||
// write to stdin
|
||
child.write("message from Rust\n".as_bytes()).unwrap();
|
||
}
|
||
}
|
||
});
|
||
```
|
||
|
||
You can place this code inside a Tauri command to easily pass the AppHandle or you can store a reference to the AppHandle in the builder script to access it elsewhere in your application.
|
||
|
||
## Running it from JavaScript
|
||
|
||
In the JavaScript code, import the `Command` class from the `@tauri-apps/plugin-shell` module and use the `sidecar` static method.
|
||
|
||
```javascript
|
||
import { Command } from '@tauri-apps/plugin-shell';
|
||
// `binaries/my-sidecar` is the EXACT value specified on `tauri.conf.json > tauri > bundle > externalBin`
|
||
const sidecar_command = Command.sidecar('binaries/my-sidecar');
|
||
const output = await sidecar_command.execute();
|
||
```
|
||
|
||
## Passing arguments
|
||
|
||
You can pass arguments to Sidecar commands just like you would for running normal `Command`s.
|
||
|
||
Arguments can be either **static** (e.g. `-o` or `serve`) or **dynamic** (e.g. `<file_path>` or `localhost:<PORT>`). You define the arguments in the exact order in which you'd call them. Static arguments are defined as-is, while dynamic arguments can be defined using a regular expression.
|
||
|
||
First, define the arguments that need to be passed to the sidecar command in `src-tauri/capabilities/main.json`:
|
||
|
||
```json title="src-tauri/capabilities/main.json" ins={14-31}
|
||
{
|
||
"$schema": "../gen/schemas/desktop-schema.json",
|
||
"identifier": "default",
|
||
"description": "Capability for the main window",
|
||
"windows": ["main"],
|
||
"permissions": [
|
||
"path:default",
|
||
"event:default",
|
||
"window:default",
|
||
"app:default",
|
||
"resources:default",
|
||
"menu:default",
|
||
"tray:default",
|
||
{
|
||
"identifier": "shell:allow-execute",
|
||
"allow": [
|
||
{
|
||
"args": [
|
||
"arg1",
|
||
"-a",
|
||
"--arg2",
|
||
{
|
||
"validator": "\\S+"
|
||
}
|
||
],
|
||
"cmd": "",
|
||
"name": "binaries/my-sidecar",
|
||
"sidecar": true
|
||
}
|
||
]
|
||
},
|
||
"shell:allow-open"
|
||
]
|
||
}
|
||
```
|
||
|
||
:::note
|
||
If you are migrating from Tauri v1, the `migrate` command in Tauri v2 CLI should take care of this for you. Read [Automated Migration](/start/migrate/from-tauri-1/#automated-migration) for more.
|
||
:::
|
||
|
||
Then, to call the sidecar command, simply pass in **all** the arguments as an array.
|
||
|
||
In Rust:
|
||
|
||
```rust
|
||
use tauri_plugin_shell::ShellExt;
|
||
#[tauri::command]
|
||
async fn call_my_sidecar(app: tauri::AppHandle) {
|
||
let sidecar_command = app.shell()
|
||
.sidecar("my-sidecar")
|
||
.unwrap()
|
||
.args(["arg1", "-a", "--arg2", "any-string-that-matches-the-validator"]);
|
||
let (mut _rx, mut _child) = sidecar_command.spawn().unwrap();
|
||
}
|
||
```
|
||
|
||
In JavaScript:
|
||
|
||
```javascript
|
||
import { Command } from '@tauri-apps/plugin-shell';
|
||
// `binaries/my-sidecar` is the EXACT value specified on `tauri.conf.json > tauri > bundle > externalBin`
|
||
// notice that the args array matches EXACTLY what is specified on `tauri.conf.json`.
|
||
const command = Command.sidecar('binaries/my-sidecar', [
|
||
'arg1',
|
||
'-a',
|
||
'--arg2',
|
||
'any-string-that-matches-the-validator',
|
||
]);
|
||
const output = await command.execute();
|
||
```
|
||
|
||
:::note
|
||
|
||
Example: For a set of arguments like: `-i /path/to/input.png -o /path/to/output.txt`, the arguments array would look like –
|
||
|
||
```json
|
||
["-i", { "validator": "\\S+" }, "-o", { "validator": "\\S+" }]
|
||
```
|
||
|
||
Here, the first and third arguments are static (`-i` and `-o`), but the second and fourth are dynamic and match the regex pattern described (`\\S+` means anything except space).
|
||
|
||
:::
|