Using cargo-deb and cargo-rpm with multiple binaries

I've got a workspace with several binaries. I would like to create debian and rpm packages with a specific project name and want to pack the binaries into these packages.
How do I have to setup the file structure and the Cargo.toml to achieve this?

1 Like

I've found the solution after lot's of trial and error.
The solution is to put all the metadata into the root Cargo.toml. The project consists of 1 library and 2 binaries.

Cargo.toml in root:

[workspace]

members = [
    "foolib",
    "foobin",
    "barbin"
]

[package]
name = "ProjectName"
version = "0.1.0"
authors = ["Jack The Ripper <jdr@mail.com>"]
edition = "2018"
license = "GPL-3.0"
description = "A sample project."

[package.metadata.deb]
maintainer = "Jack The Ripper <jdr@mail.com>"
copyright = "2020, Jack The Ripper <jdr@mail.com>"
license-file = ["LICENSE", "0"]
changelog = "Changelog.md"
revision = "1"
extended-description = """\
A sample project."""
depends = ""
section = "utility"
priority = "optional"
assets = [
    ["../../.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/libstd-6e0e72ef3f331f94.so", "/lib/x86_64-linux-gnu/", "644"],
    ["target/release/libfoolib.so", "/lib/x86_64-linux-gnu/", "644"],
    ["target/release/foobin", "/usr/bin/", "755"],
    ["target/release/barbin", "/usr/bin/", "755"],
    ["ReadMe.md", "usr/share/doc/zarc/ReadMe.md", "644"],
]

[package.metadata.rpm]
package = "SampleProject"

[package.metadata.rpm.cargo]
buildflags = ["--release"]

[package.metadata.rpm.targets]
zarc = { path = "/usr/bin/foobin" }
zarf = { path = "/usr/bin/barbin" }

[package.metadata.rpm.files]
"../../../.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/libstd-6e0e72ef3f331f94.so" = { path = "/lib/x86_64-linux-gnu/std.so" }
"../target/release/libfoolib.so" = { path = "/lib/x86_64-linux-gnu/foolib.so" }
"../LICENSE" = { path = "/usr/share/doc/SampleProject/LICENSE" }
"../ReadMe.md" = { path = "/usr/share/doc/SampleProject/ReadMe.md" }

There must exist a src/main.rs with at least an empty main function. Otherwise cargo rpm init would fail.

In directory .rpm in file SampleProject.spec I had to add the following lines at the end:

/lib/x86_64-linux-gnu/*
%{_docdir}/*

Now cargo deb and cargo rpm build are working like a charm.

I've also added a file for Wix tool on Windows to create an MSI installer. The file main.wxs is placed in folder wix:

<?xml version='1.0' encoding='windows-1252'?>
<?if $(var.Platform) = x64 ?>
    <?define Win64 = "yes" ?>
    <?define PlatformProgramFilesFolder = "ProgramFiles64Folder" ?>
<?else ?>
  <?define Win64 = "no" ?>
  <?define PlatformProgramFilesFolder = "ProgramFilesFolder" ?>
<?endif ?>

<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
    <Product
        Id='*'
        Name='SampleProject'
        UpgradeCode='<Guid>'
        Manufacturer='Jack The Ripper'
        Language='1033'
        Codepage='1252'
        Version='$(var.Version)'>

        <Package Id='*'
            Keywords='Installer'
            Manufacturer='Jack The Ripper'
            InstallerVersion='450'
            Languages='1033'
            Compressed='yes'
            InstallScope='perMachine'
            SummaryCodepage='1252'
            Platform='$(var.Platform)'/>

        <MajorUpgrade
            Schedule='afterInstallInitialize'
            DowngradeErrorMessage='A newer version of [ProductName] is already installed. Setup will now exit.'/>

        <Media Id='1' Cabinet='media1.cab' EmbedCab='yes' DiskPrompt='CD-ROM #1'/>
        <Property Id='DiskPrompt' Value='SampleProject Installation'/>

        <Directory Id='TARGETDIR' Name='SourceDir'>
            <Directory Id='$(var.PlatformProgramFilesFolder)' Name='PFiles'>
                <Directory Id='APPLICATIONFOLDER' Name='SampleProject'/>
            </Directory>
            <Directory Id='ProgramMenuFolder' Name='SampleProject'>
                <Directory Id='StartMenuFolder' Name='SampleProject'/>
            </Directory>
        </Directory>

        <DirectoryRef Id='APPLICATIONFOLDER'>
            <Component Id='Path' Guid='<Guid>' Win64='$(var.Win64)' KeyPath='yes'>
                <Environment
                    Id='PATH'
                    Name='PATH'
                    Value='[Bin]'
                    Permanent='no'
                    Part='last'
                    Action='set'
                    System='yes'/>
            </Component>
            <Component Id='License' Guid='*' Win64='$(var.Win64)'>
                <File Id='LicenseFile' Name='LICENSE' DiskId='1' Source='LICENSE' KeyPath='yes'/>
            </Component>
            <Component Id='ReadMe' Guid='*' Win64='$(var.Win64)'>
                <File Id='ReadMeFile' Name='ReadMe.md' DiskId='1' Source='ReadMe.md' KeyPath='yes'/>
            </Component>
            <Component Id='zarlib' Guid='*' Win64='$(var.Win64)'>
                <File
                    Id='foolib'
                    Name='foolib.dll'
                    DiskId='1'
                    Source='target\$(var.Profile)\foolib.dll'
                    KeyPath='yes'
                    Checksum='yes'/>
            </Component>
            <Component Id='std.dll' Guid='*' Win64='$(var.Win64)'>
                <File
                    Id='std.dll'
                    Name='std-ac6761229bc36bc9.dll'
                    DiskId='1'
                    Source='$(env.USERPROFILE)\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\bin\std-ac6761229bc36bc9.dll'
                    KeyPath='yes'
                    Checksum='yes'/>
            </Component>
            <Component Id='zarc' Guid='*' Win64='$(var.Win64)'>
                <File
                    Id='zarc'
                    Name='foobin.exe'
                    DiskId='1'
                    Source='target\$(var.Profile)\foobin.exe'
                    KeyPath='yes'
                    Checksum='yes'/>
            </Component>
            <Component Id='zarf' Guid='*' Win64='$(var.Win64)'>
                <File
                    Id='zarf'
                    Name='barbin.exe'
                    DiskId='1'
                    Source='target\$(var.Profile)\barbin.exe'
                    KeyPath='yes'
                    Checksum='yes'/>
            </Component>
            <Component Id="ApplicationShortcut" Guid="*" Win64='$(var.Win64)'>
                <Shortcut Id="ApplicationStartMenuShortcut"
                    Name="SampleProject"
                    Description="A sample project"
                    Target="[APPLICATIONFOLDER]barbin.exe"
                    WorkingDirectory="APPLICATIONFOLDER"/>
                <Shortcut Id="UninstallProduct"
                    Name="Uninstall SampleProject"
                    Description="Uninstalls SampleProject"
                    Target="[System64Folder]msiexec.exe"
                    Arguments="/x [ProductCode]"/>
                <RegistryValue Root="HKLM" Key="Software\JDR\SampleProject" Name="installed" Type="integer" Value="1" KeyPath="yes"/>
            </Component>
            <Component Id="Uninstall" Win64="yes" Guid='<Guid>'>
                <RemoveFolder Id="RemoveAPPLICATIONFOLDER" Directory="APPLICATIONFOLDER" On="uninstall"/>
                <RemoveFolder Id="RemoveStartMenuFolder" Directory="StartMenuFolder" On="uninstall"/>
            </Component>
        </DirectoryRef>

        <Feature
            Id='Binaries'
            Title='Application'
            Description='Installs all files.'
            Level='1'
            ConfigurableDirectory='APPLICATIONFOLDER'
            AllowAdvertise='no'
            Display='expand'
            Absent='disallow'>

            <ComponentRef Id='License'/>
            <ComponentRef Id='ReadMe'/>
            <ComponentRef Id='std.dll'/>
            <ComponentRef Id='foolib'/>
            <ComponentRef Id='foobin'/>
            <ComponentRef Id='barbin'/>
            <ComponentRef Id='ApplicationShortcut'/>
            <ComponentRef Id='Uninstall'/>

            <Feature
                Id='Environment'
                Title='PATH Environment Variable'
                Description='Add the install location of the [ProductName] executable to the PATH system environment variable. This allows the [ProductName] executable to be called from any location.'
                Level='1'
                Absent='allow'>
                <ComponentRef Id='Path'/>
            </Feature>
        </Feature>
        <SetProperty Id='ARPINSTALLLOCATION' Value='[APPLICATIONFOLDER]' After='CostFinalize'/>
            <Publish Dialog='WelcomeDlg' Control='Next' Event='NewDialog' Value='CustomizeDlg' Order='99'>1</Publish>
            <Publish Dialog='CustomizeDlg' Control='Back' Event='NewDialog' Value='WelcomeDlg' Order='99'>1</Publish>
        </UI>
    </Product>
</Wix>
1 Like

Unfortunately the solution above does not work as expected. cargo build and cargo run are now broken. Any help?

Ok finally I've found the solution. I've created a directory ProjectName within ProjectName. Then I split Cargo.toml in root and moved everything but workspace into the new sub directory. I've also moved directories src, .rpm and wix.
Now everything works as expected.

1 Like