Для следующего этапа проекта мне нужны режанные привязки к овладение . В этом посте я создадим ящик ржавчины с привязками и настройкой Appveyer, чтобы выполнить сборки Windows и Travis, чтобы сделать сборки OSX/Linux.
Исходный код: Github/Jeikabu/Runng-Sys Отказ
Ржавчина FFI.
Интерфейс внешнего функционала (FFI) — это то, как вы можете позвонить к/от ржавчины и другого языка программирования . Это похоже на Java Java-Native-интерфейс (JNI) , .NET’s C ++/CLI или Pinvoke и другие механизмы во многих других языках программирования.
BindGen Может автоматически генерировать чертежные привязки FFI к библиотекам C (и некоторых C ++). К счастью, NNG C. Этот блог пост ссылается на несколько мест и выглядит как происхождение Bindgen Учебное пособие Отказ
Но сначала нам нужна библиотека для RUSTC, чтобы связаться. Нам снова повезет, потому что NNG использует ума и CMAKE-RS позволяет нам запустить его от ржавчины.
грузовые новые --либы rung-sys создать новый проект и в ./Cargo.toml :
[build-dependencies] cmake = "0.1" bindgen = "0.40"
После учебника Bindgen ./wrapper.h Включает файлы заголовка NNG:
#include "nng/src/nng.h" // protocols #include "nng/src/protocol/bus0/bus.h" #include "nng/src/protocol/pipeline0/pull.h" #include "nng/src/protocol/pipeline0/push.h" #include "nng/src/protocol/pubsub0/pub.h" #include "nng/src/protocol/pubsub0/sub.h" #include "nng/src/protocol/reqrep0/rep.h" #include "nng/src/protocol/reqrep0/req.h" // transports #include "nng/src/transport/inproc/inproc.h" #include "nng/src/transport/ipc/ipc.h" #include "nng/src/transport/tcp/tcp.h" #include "nng/src/transport/ws/websocket.h"
./build.rs будет построен и выполнен до остальной части ящика:
extern crate bindgen;
extern crate cmake;
use cmake::Config;
use std::{
env,
path::PathBuf,
};
fn main() {
// Run cmake to build nng
let dst = Config::new("nng")
.generator("Ninja")
.define("CMAKE_BUILD_TYPE", "Release")
.define("NNG_TESTS", "OFF")
.define("NNG_TOOLS", "OFF")
.build();
// Check output of `cargo build --verbose`, should see something like:
// -L native=/path/runng/target/debug/build/runng-sys-abc1234/out
// That contains output from cmake
println!("cargo:rustc-link-search=native={}", dst.join("lib").display());
// Tell rustc to use nng static library
println!("cargo:rustc-link-lib=static=nng");
let bindings = bindgen::Builder::default()
.header("wrapper.h")
// This is needed if use `#include ` instead of `#include "path/nng.h"`
//.clang_arg("-Inng/src/")
.generate()
.expect("Unable to generate bindings");
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings");
}
SRC/lib.rs содержит:
// Suppress the flurry of warnings caused by using "C" naming conventions
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
// This matches bindgen::Builder output
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
Беги грузовые сборки к:
Используйте Cmake и ниндзя построить NNG. Это похоже на работу:
Запустите BINDGEN для генерации нативных библиотечных привязки в
$ Out_dir/bindings.rs
Примечания:
- Cmake Docs и Bindgen Docs Отказ
- Ниндзя — это Рекомендуемый генератор CMake для NNG.
- Иман, и ниндзя должны быть в
ПутьПеременная среды (или наборCmakeиCmake_make_programНесомненно - Отладка с
Грузовой сборной --вербаоз - CMake генерирует статическую библиотеку:
Target/Config/build/runng-sys-abc123/out/lib/libnng.a(на OSX и, вероятно, Linux). - Если решите использовать
#includeи т. Д. Вместо этого нужно снабжать включить путь черезclang_arg ()(см. это Итак, ). $ Out_dirустанавливается грузом.
Тестовая связывание
Чтобы написать простой тест, нужно посмотреть на то, что было только сгенерировано, это VS код (на OSX должен сначала Установить команду «Код» в пути ):
code `find . -name bindings.rs`
Это будет «заминировано» исходный код ржавчины. Чтобы сделать это читаемым, Просмотр> Палитра команд> Форматировать документ .
Напишите простой запрос/ответ NNG/ответ/сервер:
use std::ffi::CString;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
unsafe {
let url = CString::new("inproc://test").unwrap();
let url = url.as_bytes_with_nul().as_ptr() as *const i8;
// Reply socket
let mut rep_socket = nng_socket { id: 0 };
assert_eq!(0, nng_rep0_open(&mut rep_socket));
assert_eq!(0, nng_listen(rep_socket, url, std::ptr::null_mut(), 0));
// Request socket
let mut req_socket = nng_socket { id: 0 };
assert_eq!(0, nng_req0_open(&mut req_socket));
assert_eq!(0, nng_dial(req_socket, url, std::ptr::null_mut(), 0));
// Send message
let mut req_msg = nng_msg { _unused: [] };
let mut req_msg = &mut req_msg as *mut nng_msg;
assert_eq!(0, nng_msg_alloc(&mut req_msg, 0));
// Add a value to the body of the message
let val = 0x12345678;
assert_eq!(0, nng_msg_append_u32(req_msg, val));
assert_eq!(0, nng_sendmsg(req_socket, req_msg, 0));
// Receive it
let mut recv_msg = nng_msg { _unused: [] };
let mut recv_msg = &mut recv_msg as *mut nng_msg;
assert_eq!(0, nng_recvmsg(rep_socket, &mut recv_msg, 0));
// Remove our value from the body of the received message
let mut recv_val: u32 = 0;
assert_eq!(0, nng_msg_trim_u32(recv_msg, &mut recv_val));
assert_eq!(val, recv_val);
// Can't do this because nng uses network order (big-endian)
//assert_eq!(val, *(nng_msg_body(recv_msg) as *const u32));
nng_close(req_socket);
nng_close(rep_socket);
}
}
}
Использование CString Создание строк в NULL, как предложено это так . Чтобы получить const char * к «ABC \ 0» в ржавчине требуется:
let cstring = std::ffi::CString::new("abc").unwrap().as_bytes_with_nul().as_ptr() as *const i8;
Бороться с использованием Тип ** . в C. Например, nng_msg_alloc () Привязка:
pub fn nng_msg_alloc(arg1: *mut *mut nng_msg, arg2: usize) -> ::std::os::raw::c_int;
Чтобы получить * MUT * MUT :
// NO; can't convert &mut &mut to *mut *mut let msg = &mut &mut recv_msg as *mut *mut nng_msg; // Yes let msg = &mut (&mut recv_msg as *mut nng_msg) as *mut *mut nng_msg; // Yes let msg = &mut (&mut recv_msg as *mut nng_msg);
Последняя строка — это облегчение, Как * Mut * Mut Type это литье слова.
Опекун
Уже использую Опдерер на Другой проект Так решил начать с этого.
Использование Это appveyor.yml для ржавчины в качестве отправной точки:
image:
- Visual Studio 2017
- Ubuntu
# Build configurations
environment:
matrix:
# Stable 64-bit MSVC
- target: x86_64-pc-windows-msvc
channel: stable
# Stable 32-bit MSVC
- target: i686-pc-windows-msvc
channel: stable
# Dummy target so linux always has something to build
- target: ubuntu-dummy
channel: stable
matrix:
exclude:
# Linux ignore windows builds
- image: Ubuntu
target: x86_64-pc-windows-msvc
- image: Ubuntu
target: i686-pc-windows-msvc
# Windows should ignore dummy linux configuration
- image: Visual Studio 2017
target: ubuntu-dummy
# Platform-specific configuration
for:
-
matrix:
only:
- image: Visual Studio 2017
install:
# Download rustup and install rust
- appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
- rustup-init -yv --default-toolchain %channel% --default-host %target%
- set PATH=%PATH%;%USERPROFILE%\.cargo\bin
# Install ninja (used to build nng)
- choco install ninja
-
matrix:
only:
- image: Ubuntu
install:
- sudo apt-get update
# Need cmake/ninja/clang to build nng
- sudo apt-get --yes install cmake ninja-build build-essential clang-3.9
# Download and run rustup to install Rust (need "-y" to avoid waiting for input)
- curl https://sh.rustup.rs -sSf > rustup-init.sh
- sh rustup-init.sh -y
# Add cargo to PATH
- source $HOME/.cargo/env
# Skip build step since `cargo test` does it
build: false
test_script:
# Run only our tests (bindgen also generates tests)
- cargo test --verbose -- "tests::"
Все Матрица: вещи неудачны. Я пытался разместить окружающая среда Узел внутри для Но это не привело к созданию перестановок. Итак, переместил его и Матрица: исключить: Удалить Windows сборки на Linux и наоборот.
Использовать для Узел, чтобы иметь Различная конфигурация для каждой матрицы сборки Отказ
x86_64-pc-windows-msvc построить неудачу с:
-------- stderr
CMake Error at CMakeLists.txt:30 (project):
Generator
Ninja
does not support toolset specification, but toolset
host=x64
was specified.
Конечно, сверх то есть:
running: "cmake" "C:\\projects\\runng\\nng" "-Thost=x64" "-G" "Ninja" ...
Это вызвано Недавние изменения это добавляет -Тоность = х64 При компиляции x86_64-pc-windows-msvc Отказ Представил PR Чтобы избежать Точка с ниндзя.
I686-PC-Windows-MSVC (32-битная) сборка становится дальше неудачной с:
CMake Warning:
Manually-specified variables were not used by the project:
CMAKE_CXX_COMPILER
thread 'main' panicked at 'Unable to find libclang: "couldn\'t find any of [\'clang.dll\', \'libclang.dll\'], set the LIBCLANG_PATH environment variable to a path where one of these files can be found (skipped: [(C:\\Program Files\\LLVM\\bin\\libclang.dll: invalid DLL (64-bit))])"', libcore\result.rs:945:5
LLVM уже установлен и он нашел C: \ Program Files \ LLVM \ bin \ libclang.dll Но это 64-битное, когда нам нужно 32-битное. Похоже, мне придется вручную установить 32-битный LLVM …
Трэвис
В процессе расследования кода Rust Coverage я узнал Трэвис CI есть Явная поддержка ржавчины Отказ
Может легко настроить сборку без вощения с Rustup-init с помощью .travis.yml похожий на:
language: rust
rust:
- stable
#- nightly
os:
- linux
- osx
sudo: false
addons:
apt:
packages:
# To build nng
- cmake
- ninja-build
script:
- cargo build
- cargo test -- "tests::"
Я явно избегаю Sudo Чтобы включить Контейнеретная среда Отказ В частности, используя Аддоны: APT: установить пакеты вместо sudo apt-get install Отказ
Использовать - «Испытания::» с Грузовый тест фильтровать тесты BINDGEN. Один из тех тестов не проходит в Трэвисе по какой-то причине.
Эта сборка завершается быстро; занимает чуть более 2 минут, в то время как Appworeor занимает более 4 (в основном для установки Clang/LLVM).
Код покрытия
Вещи становятся грязными с покрытием кода.
Есть два хороших сообщения, детализирующие ржавчину CI с Трэвисом: Первый , Второй Отказ Оба стоят читать и деталь использовать KCOV для кодового покрытия. Трэвис использует Ubuntu 14.04 (Trusty Tahr), поэтому версия KCOV установлена с APT, слишком стар, чтобы работать с ржавчиной.
В .travis.yml.yml.yml :
language: rust
rust:
- stable
os:
- linux
- osx
# Force full VM (kcov doesn't work in default container environment)
sudo: required
addons:
apt:
packages:
# To build nng
- cmake
- ninja-build
# To build kcov
- libcurl4-openssl-dev
- libelf-dev
- libdw-dev
- gcc
- binutils-dev
- libiberty-dev
before_install:
# Using `source` so can update PATH environment variable
- source ./scripts/install.sh
script:
- cargo build
- cargo test -- "tests::"
after_success:
- ./scripts/after_success.sh
install.sh Вручную устанавливает ниндзя на OSX в Избегайте использования домелки :
#!/usr/bin/env bash
if [["$TRAVIS_OS_NAME" == "osx"]]; then
# `brew install ninja` requires `brew update` which takes ages....
wget https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-mac.zip
unzip ninja-mac.zip
export PATH=`pwd`:$PATH
fi
After_success Шаг запускает код Code только на успешных сборках . all_success.sh приходит от CodeCov Пример для ржавчины и Трэвиса (Также см. Примечания KCOV на Codecov ):
#!/usr/bin/env bash
TARBALL="v36.tar.gz"
KCOV_DIR="kcov-36"
if [["$TRAVIS_OS_NAME" == "linux"]]; then
# https://github.com/codecov/example-rust
wget https://github.com/SimonKagstrom/kcov/archive/$TARBALL
tar xzf $TARBALL
cd $KCOV_DIR
mkdir build
cd build
cmake ..
make
make install DESTDIR=../../kcov-build
cd ../../
rm -rf $KCOV_DIR
for file in target/debug/runng_sys-*[^\.d]; do
mkdir -p "target/cov/$(basename $file)"
# Arguments at the end are what would be passed to `cargo test`
./kcov-build/usr/local/bin/kcov --exclude-pattern=/.cargo,/usr/lib --verify "target/cov/$(basename $file)" "$file" -- "tests::"
done
# Upload reports in current directory
# https://github.com/SimonKagstrom/kcov/blob/master/doc/codecov.md
bash <(curl -s https://codecov.io/bash)
fi
Это немного отличается от Пример кодекава :
- Установите выпуск KCOV, а не Master GitHub
- Избегайте длинной цепочки, используя
И - Прохождение
- «Испытания::»args, как когда бегиГрузовый тест
В первом запуске отчет охвата был пустым, а журнал сборки содержится:
Can't set personality: Operation not permitted kcov: error: Can't start/attach to /home/travis/build/jeikabu/runng/target/debug/runng_sys-ee3c607355e4b215 Child hasn't stopped: ff00 kcov: error: Can't start/attach to /home/travis/build/jeikabu/runng/target/debug/runng_sys-ee3c607355e4b215
Посмотреть Этот выпуск Github (и Блог, упомянутый выше ). По сути, KCOV не работает в контейнерах, если только Docker не работает с определенными вариантами. Там, кажется, не так, чтобы сделать Трэвис сделать это, так что Sudo: Требуется использует полную виртуальную машину и избегает проблемы.
Ящики с Flair.
Добавить Упаковка и проект Meta-data к Cargo.toml :
[package]
name = "runng-sys"
version = "0.1.1"
description = "Bindings to nng (Nanomsg-Next-Generation) aka Nanomsg2"
keywords = ["nng", "nanomsg"]
license = "MIT"
repository = "https://github.com/jeikabu/runng-sys"
[badges]
appveyor = { repository = "jake-ruyi/runng-sys", branch = "master", service = "github" }
travis-ci = { repository = "jeikabu/runng-sys", branch = "master" }
codecov = { repository = "jeikabu/runng-sys", branch = "master", service = "github" }
Репозиторий Значения, являющиеся Владелец/проект Значения из Опдерер , Трэвис и Кодеков , соответственно.
груз публикует Пакеты привязки как ящик и загрузите его на Craites.io :
Плавник
Я искушал бегать KCOV на OSX, поэтому я могу использовать контейнерную среду Linux. Но я спрашиваю вопрос о мудрости бега KCOV на «менее рекомендуемой» платформе просто для фактора Neat-O.
Хотел бы собрать PR для NNG-SYS CRATE Отказ
Нужно сделать обертку высокого уровня вокруг привязки NNG, чтобы скрыть небезопасных/указателей Shenanigans. Скорее всего, смодели к этому после не Netcore Отказ
Оригинал: «https://dev.to/jeikabu/rust-ffi-crate-and-ci-2n05»