trunnion / cargo-acap

A tool to build Rust programs for the AXIS Camera Application Platform
Apache License 2.0
11 stars 5 forks source link

README instructions are outdated? #1

Open bes opened 3 years ago

bes commented 3 years ago

Hi,

I was looking forward to testing this project to see if I could get Rust running as an ACAP app.

I had some troubles getting this up and running, mainly that cargo install cargo-acap doesn't work since there is no cargo-acap on crates.io.

I tried building cargo-acap from source but after cloning cargo-acap and vapix, updating Cargo.toml with vapix = { path = "../vapix", version = "0.1.1-alpha.0", features = ["goblin"] } and running cargo install --path cargo-acap I got a build error:

cargo install --path .
  Installing cargo-acap v0.1.0 (/Users/bes/repos/github/cargo-acap)
    Updating crates.io index
    Updating git repository `https://github.com/willglynn/goblin.git`
   Compiling cargo v0.47.0
error[E0283]: type annotations needed
   --> /Users/bes/.cargo/registry/src/github.com-1ecc6299db9ec823/cargo-0.47.0/src/cargo/util/config/de.rs:491:63
    |
491 |                 seed.deserialize(Tuple2Deserializer(1i32, env.as_ref()))
    |                                                           ----^^^^^^--
    |                                                           |   |
    |                                                           |   cannot infer type for type parameter `T` declared on the trait `AsRef`
    |                                                           this method call resolves to `&T`
    |
    = note: cannot satisfy `std::string::String: AsRef<_>`
help: use the fully qualified path for the potential candidates
    |
491 |                 seed.deserialize(Tuple2Deserializer(1i32, <std::string::String as AsRef<OsStr>>::as_ref(env)))
    |                                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
491 |                 seed.deserialize(Tuple2Deserializer(1i32, <std::string::String as AsRef<std::path::Path>>::as_ref(env)))
    |                                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
491 |                 seed.deserialize(Tuple2Deserializer(1i32, <std::string::String as AsRef<[u8]>>::as_ref(env)))
    |                                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
491 |                 seed.deserialize(Tuple2Deserializer(1i32, <std::string::String as AsRef<str>>::as_ref(env)))
    |                                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0283`.
error: failed to compile `cargo-acap v0.1.0 (/Users/bes/repos/github/cargo-acap)`, intermediate artifacts can be found at `/Users/bes/repos/github/cargo-acap/target`

Caused by:
  could not compile `cargo`

To learn more, run the command again with --verbose.

Which commits of cargo-acap and vapix should I use for building?

Furthermore I could not find any version of cargo-acap-build on docker hub? Maybe the files are on another registry, or do I have build the image (and multiple versions of rust) manually using the Dockerfile in cargo-acap-build. I am kind of surprised that there isn't an easier way of doing this than building Rust from scratch?

Thanks.

willglynn commented 3 years ago

I was looking forward to testing this project to see if I could get Rust running as an ACAP app. […] Which commits of cargo-acap and vapix should I use for building?

I will look into this later tonight, probably including cutting a release of each.

You might also want to know that I had been working on Rust bindings to the ACAP libraries. I don't remember exactly the status of that but I'll see if I can't push what I have without being too embarrassed 😄

Furthermore I could not find any version of cargo-acap-build on docker hub?

There's a variety of tags on trunnion/cargo-acap. cargo-acap ought to pull the version corresponding to your usual rustc automatically… once you have a working copy of cargo-acap.

I am kind of surprised that there isn't an easier way of doing this than building Rust from scratch?

rustc supports custom targets on nightly. I like Rust's release cycle and didn't want to require nightly just for a MIPS target that's smack in the middle of the supported MIPS targets, so I figured building stable rustc with an extra target would be a better fit. By duplicating some of the existing target triples, this can also enable #[cfg(target_vendor = "axis")].

Suppose the other way: use nightly with custom targets. That avoids needing build rustc, but does not avoid needing to build std, which is rather lengthy. It also doesn't avoid needing a GNU toolchain for each target, which for the MIPS target is either a) an exciting adventure in cross-compiler installation or b) usage of the Linux toolchain provided by Axis in SDK2.

Building a rustc+std for each stable release (extended to support extra targets) and packaging everything into a container image along with the appropriate toolchains seemed like the best solution.

bes commented 3 years ago

Thanks for the explanation! I would be really happy to have a look at your Rust bindings 👍

You write "Axis SDK2", how does that relate to "ACAP 3" as mentioned here https://hub.docker.com/r/axisecp/acap-toolchain ?

willglynn commented 3 years ago

Axis changed a bunch of stuff when they released ACAP 3. If you had a C/C++ application, you'd have to make significant changes to your build process to transition from building ACAP 2 to ACAP 3.

ACAP 3 dropped support for the CRIS cameras (ARTPEC 1-3) which haven't been sold in ages, but also dropped support for MIPS cameras (ARTPEC 4-5) some of which aren't even EOL. The runtime environment isn't all that different, though – it's perfectly possible to make an application which works in either platform – leading to a situation where most ACAP software vendors use both SDKs to avoid unnecessarily reducing compatibility.

cargo-acap replaces the entire Axis ACAP build process anyway, and it doesn't care about the runtime environment at all, so for building an .eap from Rust there's really no need to distinguish. Unlike either ACAP SDK 2 or ACAP 3, cargo-acap can build executables for every camera Axis sells.

The ACAP bindings I was working on are similarly indifferent. Everything is dlopen()ed at runtime, so if you try to use an interface not supported on this camera, you get an Err() you can handle – usually by falling back to a different interface – rather than having to build two different executables.

bes commented 3 years ago

So if I were to build an ACAP application using cargo-acap, but I also had a bunch of legacy code in C, then I would have to call into the C code using FFI, instead of my initial plan which was to call Rust from C over FFI?

willglynn commented 3 years ago

cargo acap build is certainly intended to get you to an .eap. You could probably use the pieces to make a .a against which you could statically link a C application, and hooking that up with ACAP 2 and/or 3 would be… fun.

Another alternative would be to make -sys crate for your C code, write an application in Rust, and let cargo acap build build that Rust application into a bunch of .eaps. The containerized build environment has a C compiler for every target and Rust build scripts work as normal. I'm not exactly sure what the header situation is so you might have some #include-related problems, but depending on your circumstances that might be a smaller hurdle. I've definitely used Rust crates that build and link against bundled C libraries via cargo acap build.

willglynn commented 3 years ago

Given a Cargo workspace:

[workspace]
members = [
    "cargo-acap",
    "vapix",
    ]

[patch.crates-io]
vapix = { path = "./vapix" }

…where ./cargo-acap is 76edea1 and ./vapix is eac61ce, I'm able to reproduce the cargo-0.47 build failure you reported with cargo install --path ./cargo-acap, but I'm also able to get a working executable with cargo install --locked --path ./cargo-acap.

bes commented 3 years ago

Unfortunately I still get that build failure when using cargo install --locked --path ./cargo-acap

Given this directory structure:

axis% exa -T -L 1
.
├── cargo-acap
├── Cargo.toml
├── target
└── vapix

This Cargo.toml in axis:

[workspace]

members = [
    "cargo-acap",
    "vapix",
]

[patch.crates-io]
vapix = { path = "./vapix" }

And these commits from cargo-acap

axis/cargo-acap% git show --summary

commit 76edea1ef13017ddf202deee14ef3bcd98d0dc7d (HEAD -> master, origin/master, origin/HEAD)
Author: Will Glynn <will@willglynn.com>
Date:   Thu Nov 19 09:58:26 2020 -0600

    1.48.0: search for compiler/rustc_target/src/spec too

and vapix:

axis/vapix% git show --summary

commit eac61ce0bbf80e6c4ab3b9ad55960aab46fc39b1 (HEAD -> master, origin/master, origin/HEAD)
Author: Will Glynn <will@willglynn.com>
Date:   Fri Sep 3 23:45:47 2021 -0500

    Add ARTPEC-2

Running this command fails:

axis% cargo install --locked --path ./cargo-acap
warning: no Cargo.lock file published in cargo-acap v0.1.0 (/Users/bes/repos/github/axis/cargo-acap)
  Installing cargo-acap v0.1.0 (/Users/bes/repos/github/axis/cargo-acap)
    Updating crates.io index
    Updating git repository `https://github.com/willglynn/goblin.git`
warning: field is never read: `device`
  --> vapix/src/v3/recordings.rs:16:5
   |
16 |     device: &'a Client<T>,
   |     ^^^^^^^^^^^^^^^^^^^^^
   |
   = note: `#[warn(dead_code)]` on by default

warning: field is never read: `supports_continuous_recording`
  --> vapix/src/v3/recordings.rs:17:5
   |
17 |     supports_continuous_recording: bool,
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

warning: field is never read: `supports_playback_over_rtsp`
  --> vapix/src/v3/recordings.rs:18:5
   |
18 |     supports_playback_over_rtsp: bool,
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

warning: field is never read: `supports_exporting`
  --> vapix/src/v3/recordings.rs:19:5
   |
19 |     supports_exporting: bool,
   |     ^^^^^^^^^^^^^^^^^^^^^^^^

warning: associated function is never used: `new`
  --> vapix/src/v3/recordings.rs:23:25
   |
23 |     pub(crate) async fn new(device: &'a Client<T>) -> Result<Option<Recordings<'a, T>>> {
   |                         ^^^

warning: 5 warnings emitted

   Compiling cargo v0.47.0
error[E0283]: type annotations needed
   --> /Users/bes/.cargo/registry/src/github.com-1ecc6299db9ec823/cargo-0.47.0/src/cargo/util/config/de.rs:491:63
    |
491 |                 seed.deserialize(Tuple2Deserializer(1i32, env.as_ref()))
    |                                                           ----^^^^^^--
    |                                                           |   |
    |                                                           |   cannot infer type for type parameter `T` declared on the trait `AsRef`
    |                                                           this method call resolves to `&T`
    |
    = note: cannot satisfy `std::string::String: AsRef<_>`
help: use the fully qualified path for the potential candidates
    |
491 |                 seed.deserialize(Tuple2Deserializer(1i32, <std::string::String as AsRef<OsStr>>::as_ref(env)))
    |                                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
491 |                 seed.deserialize(Tuple2Deserializer(1i32, <std::string::String as AsRef<std::path::Path>>::as_ref(env)))
    |                                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
491 |                 seed.deserialize(Tuple2Deserializer(1i32, <std::string::String as AsRef<[u8]>>::as_ref(env)))
    |                                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
491 |                 seed.deserialize(Tuple2Deserializer(1i32, <std::string::String as AsRef<str>>::as_ref(env)))
    |                                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0283`.
error: failed to compile `cargo-acap v0.1.0 (/Users/bes/repos/github/axis/cargo-acap)`, intermediate artifacts can be found at `/Users/bes/repos/github/axis/target`

Caused by:
  could not compile `cargo`

To learn more, run the command again with --verbose.
bes commented 3 years ago

I wonder if warning: no Cargo.lock file published in cargo-acap v0.1.0 (/Users/bes/repos/github/axis/cargo-acap) might be a hint?

willglynn commented 3 years ago

Ah, the Cargo.lock in my checkout was .gitignored. Try cargo-acap as of 671a5da.

bes commented 3 years ago

Great! No dice using the workspace configuration (same error, missing Cargo.lock), but modifying Cargo.toml in cargo-acap like this worked:

vapix = { path = "../vapix", version = "0.1.1-alpha.0", features = ["goblin"] }
bes commented 3 years ago

I would love to have a peek at those fabled Rust bindings to the ACAP libraries you mentioned ;)

bes commented 3 years ago

@willglynn Don't want to take up any of your time unnecessarily (I know how precious one's time is) - but if you have the chance & are willing, I would love to take a look at your ACAP bindings <3

willglynn commented 3 years ago

I'm planning to return to that sometime in the next week or two.

bes commented 2 years ago

Hey! Did you ever return to it? ❤️

johan-bjareholt commented 2 years ago

The README instructions seem to be fixed, both the crate and docker image are published on crates.io and dockerhub respectively.

The rust bindings for ACAPs do sound very useful too though!