Рубрики
Uncategorized

Rug Ffi Crate и CI

Для следующего этапа проекта мне нужны чертевые привязки к NNG. В этом посте я создадим ящик ржавчины Wi … Теги от ржавчины, FFI, DEVOPS.

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

Беги грузовые сборки к:

  1. Используйте Cmake и ниндзя построить NNG. Это похоже на работу:

  2. Запустите 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

Это немного отличается от Пример кодекава :

  1. Установите выпуск KCOV, а не Master GitHub
  2. Избегайте длинной цепочки, используя И
  3. Прохождение - «Испытания::» 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»