cargo-nuget
cargo-nuget copied to clipboard
Support cross-compilation
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.
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 noti686-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 invokingcargo-nuget
I'll spend some time playing with it and see what I come up with.
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.
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
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
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.
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