diff --git a/.travis.yml b/.travis.yml index 702eaee..fd3ed3b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,17 +6,33 @@ os: - osx - linux env: - - IOS_ARCHS="" + - IOS_ARCHS="" BLOCKS_RUNTIME=ObjC-compatible matrix: include: - os: osx osx_image: xcode7.2 rust: nightly - env: IOS_ARCHS="i386 x86_64 armv7 armv7s aarch64" + env: IOS_ARCHS="i386 x86_64 armv7 armv7s aarch64" BLOCKS_RUNTIME=ObjC-compatible + - os: linux + rust: stable + env: IOS_ARCHS="" BLOCKS_RUNTIME=Standalone + addons: + apt: + packages: + - libblocksruntime-dev + - os: linux + rust: nightly + env: IOS_ARCHS="" BLOCKS_RUNTIME=Standalone + addons: + apt: + packages: + - libblocksruntime-dev sudo: false install: ./travis_install.sh +before_script: > + if [ "$TRAVIS_OS_NAME" = "linux" ] && [ "$BLOCKS_RUNTIME" = "ObjC-compatible" ]; then + export LIBRARY_PATH=$HOME/libobjc2_staging/lib:$LIBRARY_PATH; + export LD_LIBRARY_PATH=$HOME/libobjc2_staging/lib:$LD_LIBRARY_PATH; + export CPATH=$HOME/libobjc2_staging/include:$CPATH; + fi script: ./travis_test.sh -addons: - apt: - packages: - - libblocksruntime-dev diff --git a/Cargo.toml b/Cargo.toml index f414e7e..77f2d4b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ readme = "README.md" repository = "http://github.com/SSheldon/rust-block" documentation = "http://ssheldon.github.io/rust-objc/block/" license = "MIT" +build = "build.rs" exclude = [ ".gitignore", @@ -18,6 +19,9 @@ exclude = [ "tests-ios/**", ] +[target.'cfg(not(any(target_os = "macos", target_os = "ios")))'.build-dependencies] +gcc = "0.3" + [dev-dependencies.objc_test_utils] version = "0.0" path = "test_utils" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..3e8ec12 --- /dev/null +++ b/build.rs @@ -0,0 +1,63 @@ +#[cfg(not(any(target_os = "macos", target_os = "ios")))] +extern crate gcc; +#[cfg(not(any(target_os = "macos", target_os = "ios")))] +use std::error::Error; +#[cfg(not(any(target_os = "macos", target_os = "ios")))] +use std::io::Write; +#[cfg(not(any(target_os = "macos", target_os = "ios")))] +use std::process::{ExitStatus,Stdio}; +#[cfg(not(any(target_os = "macos", target_os = "ios")))] +use std::result::Result; +#[cfg(not(any(target_os = "macos", target_os = "ios")))] +static MINI_MAIN: &'static str = r#" +extern void *_Block_copy(const void *aBlock); +int main() { + void (*ptr)(const void*) = _Block_copy; + return 0; +}"#; + +#[cfg(any(target_os = "macos", target_os = "ios"))] +fn main() { + println!("cargo:rustc-link-lib=framework=System") +} + +#[cfg(not(any(target_os = "macos", target_os = "ios")))] +fn check_block_copy_symbol_in_lib(library: &str) -> Result<(),String> { + let invocation_result = gcc::Config::new() + .compiler("clang") + .get_compiler().to_command() + .arg(format!("-l{}", library)) + .args(&["-x", "c"]) + .args(&["-o", "/dev/null"]) + .arg("-") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn(); + if invocation_result.is_err() { + return Result::Err("Could not spawn compiler".to_string()) + } + let mut process = invocation_result.unwrap(); + if let Err(why) = process.stdin.take().unwrap().write_all(MINI_MAIN.as_bytes()) { + return Result::Err(format!("Could not compile: {}", why.description())) + } + process.wait() + .or(Result::Err("Failed to compile".to_string())) + .and_then(| status : ExitStatus| if status.success() { + Result::Ok(()) + } else { + Result::Err(format!("{} unavailable", library)) + }) +} + + +#[cfg(not(any(target_os = "macos", target_os = "ios")))] +fn main() { + if check_block_copy_symbol_in_lib("objc").is_ok() { + println!("cargo:rustc-link-lib=objc") + } else if let Err(why) = check_block_copy_symbol_in_lib("BlocksRuntime") { + panic!("Could not find blocks runtime library: {}", why) + } else { + println!("cargo:rustc-link-lib=BlocksRuntime") + } + +} diff --git a/src/lib.rs b/src/lib.rs index b9c5d1d..2ffc9ce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,10 +56,6 @@ use std::ptr; enum Class { } -#[cfg_attr(any(target_os = "macos", target_os = "ios"), - link(name = "System", kind = "dylib"))] -#[cfg_attr(not(any(target_os = "macos", target_os = "ios")), - link(name = "BlocksRuntime", kind = "dylib"))] extern { static _NSConcreteStackBlock: Class; diff --git a/test_utils/block_utils.c b/test_utils/block_utils.c index 440dbb9..84b47d6 100644 --- a/test_utils/block_utils.c +++ b/test_utils/block_utils.c @@ -1,5 +1,9 @@ #include +#if __has_include("Block.h") #include +#elif __has_include("objc/blocks_runtime.h") +#include +#endif typedef int32_t (^IntBlock)(); typedef int32_t (^AddBlock)(int32_t); diff --git a/travis_install.sh b/travis_install.sh index 27c11fe..f0ad32a 100755 --- a/travis_install.sh +++ b/travis_install.sh @@ -9,6 +9,16 @@ rust_ios_install() { "./${ios_stdlib}/install.sh" --prefix=$(rustc --print sysroot) } +gnustep_install() { + git clone https://github.com/gnustep/libobjc2.git + mkdir libobjc2/build + cd libobjc2/build + export CC="clang" + export CXX="clang++" + cmake -DCMAKE_INSTALL_PREFIX:PATH=$HOME/libobjc2_staging ../ + make install +} + for arch in $IOS_ARCHS; do rust_ios_install "$arch" done @@ -17,3 +27,7 @@ if [ -n "$IOS_ARCHS" ]; then curl -LO https://github.com/SSheldon/rust-test-ios/releases/download/0.1.1/rust-test-ios chmod +x rust-test-ios fi + +if [ "$TRAVIS_OS_NAME" = "linux" ] && [ "$BLOCKS_RUNTIME" = "ObjC-compatible" ]; then + gnustep_install +fi