cargo-nuget icon indicating copy to clipboard operation
cargo-nuget copied to clipboard

Support cross-compilation

Open KodrAus opened this issue 7 years ago • 6 comments

Right now we've got a pack command that builds a binary for the local platform with a loose RID. We should also support cross-compilation, which means thinking about the following in more detail:

  • Converting Rust triples into .NET RIDs
  • Cross-compilation
  • Supplying pre-built Rust libraries for various targets

So something like the following workflow might work:

struct Target { triple: &str, source: TargetSource }
enum TargetSource { Build, File { path: &Path } }

The question then is how to get the target and source from command line, and how to deal with cases where the Rust triple doesn't align with a .NET RID.

You can do cross compilation in Rust with cross, but it doesn't support Windows.

There's also CI templates that produce nice cross-platform binaries, but they require a Travis and AppVeyor build, which might not be suitable for stuff that isn't open-source or already using those systems.

At this stage I'm leaning towards a cross compilation story that will try use cross, and for Windows, expect you're building on a Windows environment. For proper CI, you could use something like trust, then cargo-nuget could consume those artifacts without trying to build itself.

I'm keen to know what other people think, how they might expect cross compilation to be supported.

KodrAus avatar Mar 13 '17 05:03 KodrAus

I've spent some time thinking about this and have a design a bit like this in mind:

Cross platform

$ cargo-nuget cross --target win-x64 --win-x64-path ./out/win/app.dll --target osx-x64 --oxs-x64-path ./out/osx/libapp.dylib --target linux-x64

builds: [
    Build::Cross {
        target: Target::Win(Arch::x64),
        source: Source::Path("./out/win/app.dll")
    },
    Build::Cross {
        target: Target::Osx(Arch::x64),
        source: Source::Path("./out/osx/libapp.dylib")
    },
    Build::Cross {
        target: Target::Linux(Arch::x64),
        source: Source::Build {
            action: Action::Build,
            profile: Profile::Debug
        }
    }
]
$ cargo-nuget cross --all-platforms --osx-x64-path ./out/osx/x64/libapp.dylib --osx-x86-path ./out/osx/x86/libapp.dylib

Local

$ cargo-nuget pack --test --release

builds: [
    Build::Local {
        source:  Source::Build {
            action: Action::Test,
            profile: Profile::Release
        }
    }
]

So the idea is:

  • We use nuget rids in commands. They're a bit shorter than Rust triples and the end target is an rid anyways
  • We strongly type the target components. This is because we need to translate triple -> rid
  • A local build invokes cargo build
  • A cross build either returns the path passed in or runs cargo cross

Some other considerations:

  • For builds I don't think people care about specific platforms. They'll just want their library supported by all of them.
  • Cross supports x86_64-pc-windows-gnu, but not i686-pc-windows-gnu, or any OSX targets
  • We're only supporting a local path for a non-build cross platform target, so if you use something like trust then you'll need to figure out how to download the output binaries locally before invoking cargo-nuget

I'll spend some time playing with it and see what I come up with.

KodrAus avatar Jun 01 '17 08:06 KodrAus

I've started playing with this and am refactoring out a core input structure we can use to drive commands.

There are a few potentially nasty pieces to deal with, like if you specify --target win-x64 without a path then we'll just fall over right now because it's not supported. It would be nice to be able to support matching args by dotnet rid to build targets, but that's a future thing.

KodrAus avatar Oct 11 '17 21:10 KodrAus

Right now I'd like to get:

  • local builds working the same
  • cross builds working for well-formed rids
  • backdoor cross build that stuffs an output in an any target

KodrAus avatar Oct 11 '17 21:10 KodrAus

Would also be nice to be able to specify things using a toml config. That'll be much easier to parse into the input structure than command-line args.

Maybe for the args we should go fully conservative and require something like:

cargo-nuget cross --path-targets win-x64 linux-x64 --win-x64-path ./path/to/lib.dll --linux-x64-path ./path/to/lib.so

Then in the future we'd also have:

cargo-nuget cross --build-targets win-x64 linux-x64 --path-targets osx-x64 --osx-x64-path ./path/to/lib.dylib

KodrAus avatar Oct 11 '17 21:10 KodrAus

Ok we've got some basic cross-platform support built in by specifying the path to a pre-built binary for each target. I think this is the core use-cases because you can build those binaries on each target in question, running tests and whatnot, and then bundle them up into a package at the end.

I would also like to support cross-platform building through the tool itself somehow in the future. But I'm not certain what direction to take that in. I've got a docker container that can produce binaries for each output without a lot of fuss, but don't want to bake that in right now.

KodrAus avatar Nov 10 '17 09:11 KodrAus

There's still a bit of cleanup to do before the next release:

  • newlines in logs are a bit of a mess
  • remove the deny warnings attribute
  • add docs about the cross-platform builds
  • add cross-platform testing to CI

KodrAus avatar Nov 10 '17 09:11 KodrAus