Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding lib support to crossgen #12

Merged
merged 3 commits into from
Sep 17, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ pub struct Cli {
/// Project name. Defaults to target directory name
#[structopt(short = "n", long = "name")]
name: Option<String>,
/// Specify if a library template should be generated
#[structopt(short = "l", long = "lib")]
lib: bool,
/// Target directory
#[structopt(default_value = ".")]
dir: String,
Expand Down Expand Up @@ -58,6 +61,12 @@ impl Cli {
}
}

/// Access the lib flag.
#[inline]
pub fn lib(&self) -> bool {
self.lib
}

fn name_from_dir(&self) -> ::Result<String> {
let dir = self.dir().context(::ErrorKind::Other)?;
let dir = dir.iter().last().ok_or_else(|| ::ErrorKind::Other)?;
Expand Down
8 changes: 7 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ fn main() -> Result<(), ExitFailure> {

let dir = args.dir()?;
let name = args.name()?;
let lib = args.lib();

let manifest = TomlManifest::from_slice(&read("Cargo.toml")?)?;
let repo = manifest
Expand All @@ -38,7 +39,12 @@ fn main() -> Result<(), ExitFailure> {

let token = crossgen::authenticate(env!("CARGO_PKG_NAME"))?;
let token = crossgen::encrypt(username, project, &token)?;
let templ = crossgen::Templates::new(dir, name, token)?;
let templ = if lib {
crossgen::Templates::gen_lib(dir, name, token)
} else {
crossgen::Templates::gen_bin(dir, name, token)
}?;

templ.write_all()?;

Ok(())
Expand Down
66 changes: 55 additions & 11 deletions src/templates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,82 @@ use std::fs::File;
use std::io::prelude::*;
use std::path::PathBuf;

static DEPLOY_PS1: &str = include_str!("../templates/before_deploy.ps1");
static DEPLOY_SH: &str = include_str!("../templates/before_deploy.sh");
static INSTALL: &str = include_str!("../templates/install.sh");
static SCRIPT: &str = include_str!("../templates/script.sh");
static TRAVIS: &str = include_str!("../templates/travis.yml");
static BIN_DEPLOY_PS1: &str =
include_str!("../templates/bin/before_deploy.ps1");
static BIN_DEPLOY_SH: &str = include_str!("../templates/bin/before_deploy.sh");
static BIN_INSTALL: &str = include_str!("../templates/bin/install.sh");
static BIN_SCRIPT: &str = include_str!("../templates/bin/script.sh");
static BIN_TRAVIS: &str = include_str!("../templates/bin/travis.yml");

static LIB_DEPLOY_PS1: &str =
include_str!("../templates/lib/before_deploy.ps1");
static LIB_DEPLOY_SH: &str = include_str!("../templates/lib/before_deploy.sh");
static LIB_INSTALL: &str = include_str!("../templates/lib/install.sh");
static LIB_SCRIPT: &str = include_str!("../templates/lib/script.sh");
static LIB_TRAVIS: &str = include_str!("../templates/lib/travis.yml");
// static APPVEYOR: &str = include_str!("../templates/appveyor.yml");

/// GitHub template struct.
pub struct Templates {
name: String,
dir: PathBuf,
token: String,
lib: bool,
}

impl Templates {
/// Create a new instance. Creates a `scripts/` directory if it doesn't exist
/// already.
#[deprecated(since = "0.5.0", note = "Use `gen_bin` or `gen_lib` instead")]
pub fn new(dir: PathBuf, name: String, token: String) -> ::Result<Self> {
Self::gen_bin(dir, name, token)
}

/// Create a new instance for binary target.
pub fn gen_bin(dir: PathBuf, name: String, token: String) -> ::Result<Self> {
Self::scaffold(false, dir, name, token)
}

/// Create a new instance for library target
pub fn gen_lib(dir: PathBuf, name: String, token: String) -> ::Result<Self> {
Self::scaffold(true, dir, name, token)
}

/// Private util function that sets up the scripts dir
#[inline]
fn scaffold(
lib: bool,
dir: PathBuf,
name: String,
token: String,
) -> ::Result<Self> {
let scripts_dir = dir.join("scripts");
mkdirp(&scripts_dir).context(::ErrorKind::Other)?;
Ok(Self { name, dir, token })
Ok(Self {
lib,
name,
dir,
token,
})
}

/// Write all templates.
pub fn write_all(&self) -> ::Result<()> {
let scripts_dir = &self.dir.join("scripts");
self.write(&scripts_dir, "before_deploy.ps1", DEPLOY_PS1)?;
self.write(&scripts_dir, "before_deploy.sh", DEPLOY_SH)?;
self.write(&scripts_dir, "install.sh", INSTALL)?;
self.write(&scripts_dir, "script.sh", SCRIPT)?;

self.write(&self.dir, ".travis.yml", TRAVIS)?; // TODO: set token
if self.lib {
self.write(&scripts_dir, "before_deploy.ps1", LIB_DEPLOY_PS1)?;
self.write(&scripts_dir, "before_deploy.sh", LIB_DEPLOY_SH)?;
self.write(&scripts_dir, "install.sh", LIB_INSTALL)?;
self.write(&scripts_dir, "script.sh", LIB_SCRIPT)?;
self.write(&self.dir, ".travis.yml", LIB_TRAVIS)?; // TODO: set token
} else {
self.write(&scripts_dir, "before_deploy.ps1", BIN_DEPLOY_PS1)?;
self.write(&scripts_dir, "before_deploy.sh", BIN_DEPLOY_SH)?;
self.write(&scripts_dir, "install.sh", BIN_INSTALL)?;
self.write(&scripts_dir, "script.sh", BIN_SCRIPT)?;
self.write(&self.dir, ".travis.yml", BIN_TRAVIS)?; // TODO: set token
}

// self.write(&self.dir, "appveyor.yml", APPVEYOR)?;

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Empty file added templates/lib/appveyor.yml
Empty file.
23 changes: 23 additions & 0 deletions templates/lib/before_deploy.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# This script takes care of packaging the build artifacts that will go in the
# release zipfile.

$PKG_NAME = "{{PKG_NAME}}"
$SRC_DIR = $PWD.Path
$STAGE = [System.Guid]::NewGuid().ToString()

Set-Location $ENV:Temp
New-Item -Type Directory -Name $STAGE
Set-Location $STAGE

$ZIP = "$SRC_DIR\$($Env:CRATE_NAME)-$($Env:APPVEYOR_REPO_TAG_NAME)-$($Env:TARGET).zip"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When thinking of the distribution aspect of the lib on github, I think it would be more helpful to have the bare-ddl not zipped.

In my mind, when building a library on another language, it could be possible to instrument the build system to download all the .so and .dll into a folder to distribute the package with it, and having it not-zipped would make the build system much simpler.

What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the zip archive really only makes a big difference if you have a library that produces more than one artefact (which can easily be the case). Maybe it should be something that is configurable somehow?


Copy-Item "$SRC_DIR\target\$($Env:TARGET)\release\$PKG_NAME.exe" '.\'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On windows we might want to have this as $PKG_NAME.dll and copy it to .\win-$target-$PKG_NAME.dll as I think GitHub don't support folders


7z a "$ZIP" *

Push-AppveyorArtifact "$ZIP"

Remove-Item *.* -Force
Set-Location ..
Remove-Item $STAGE
Set-Location $SRC_DIR
32 changes: 32 additions & 0 deletions templates/lib/before_deploy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# This script takes care of building the crate and packaging it for release.

PKG_NAME="{{PKG_NAME}}"

set -ex

main() {
local src=$(pwd) \
stage=

case $TRAVIS_OS_NAME in
linux)
stage=$(mktemp -d)
;;
osx)
stage=$(mktemp -d -t tmp)
;;
esac

test -f Cargo.lock || cargo generate-lockfile

cross rustc --bin $PKG_NAME --target $TARGET --release -- -C lto
cp target/$TARGET/release/$PKG_NAME $stage/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think cargo generates libs in the form of ${PKG_NAME}lib.so

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it was lib${PKG_NAME}.so unless you manually set the lib.name field?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, you are right!


cd $stage
tar czf $src/$CRATE_NAME-$TRAVIS_TAG-$TARGET.tar.gz *
cd $src

rm -rf $stage
}

main
51 changes: 51 additions & 0 deletions templates/lib/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
set -ex

main() {
local target=
if [ $TRAVIS_OS_NAME = linux ]; then
target=x86_64-unknown-linux-musl
sort=sort
else
target=x86_64-apple-darwin
sort=gsort # for `sort --sort-version`, from brew's coreutils.
fi

# Builds for iOS are done on OSX, but require the specific target to be
# installed.
case $TARGET in
aarch64-apple-ios)
rustup target install aarch64-apple-ios
;;
armv7-apple-ios)
rustup target install armv7-apple-ios
;;
armv7s-apple-ios)
rustup target install armv7s-apple-ios
;;
i386-apple-ios)
rustup target install i386-apple-ios
;;
x86_64-apple-ios)
rustup target install x86_64-apple-ios
;;
esac

# This fetches latest stable release
local tag=$(git ls-remote --tags --refs --exit-code https://github.com/japaric/cross \
| cut -d/ -f3 \
| grep -E '^v[0.1.0-9.]+$' \
| $sort --version-sort \
| tail -n1)
curl -LSfs https://japaric.github.io/trust/install.sh | \
sh -s -- \
--force \
--git japaric/cross \
--tag $tag \
--target $target

# Install test dependencies
rustup component add rustfmt-preview
rustup component add clippy-preview
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we also install bindgen and setup a build stage responsible to build the .h headers and publish on Github?

Copy link
Owner

@yoshuawuyts yoshuawuyts Sep 14, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few quick notes here:

  • we would need cbindgen, not bindgen here (e.g. wrap rust code to be consumed from C, not the other way around)
  • here's an example of how to do that
  • in the example it stands out to me that a cbindgen.toml file is included. Should we generate that as well, or leave that up to the user? It looks like it might not be required.
  • building with cbindgen can either be done from the command line or from build.rs, I'm not sure which one is preferable. But we should probably pick one.

}

main
23 changes: 23 additions & 0 deletions templates/lib/script.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# This script takes care of testing the crate.

set -ex

main() {
cross build --target $TARGET
cross build --target $TARGET --release

if [ ! -z $DISABLE_TESTS ]; then
return
fi

cargo fmt -- --check
cargo +nightly clippy

cross test --target $TARGET
cross test --target $TARGET --release
}

# we don't run the "test phase" when doing deploys
if [ -z $TRAVIS_TAG ]; then
main
fi
55 changes: 55 additions & 0 deletions templates/lib/travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
dist: trusty
language: rust
services: docker
sudo: required

env:
global:
- CRATE_NAME={{PKG_NAME}}
- RUST_BACKTRACE=1

matrix:
include:
- env: TARGET=armv7-unknown-linux-gnueabihf
rust: nightly
- env: TARGET=x86_64-unknown-linux-musl
rust: nightly
- env: TARGET=x86_64-apple-darwin
rust: nightly
os: osx
- env: TARGET=x86_64-unknown-freebsd DISABLE_TESTS=1
rust: nightly

before_install:
- set -e

install:
- sh scripts/install.sh
- source ~/.cargo/env || true

script:
- bash scripts/script.sh

after_script: set +e

before_deploy:
- sh scripts/before_deploy.sh

deploy:
provider: releases
skip_cleanup: true
file_glob: true
file: $CRATE_NAME-$TRAVIS_TAG-$TARGET.*
api_key:
secure: "{{TOKEN}}"
on:
tags: true

cache: cargo
before_cache:
- chmod -R a+r $HOME/.cargo

notifications:
email:
on_success: never
on_failure: never