Для следующего этапа проекта мне нужны режанные привязки к овладение . В этом посте я создадим ящик ржавчины с привязками и настройкой 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»