Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into feature/allow_dupli…
Browse files Browse the repository at this point in the history
…cate_bundles_in_container
  • Loading branch information
pnoltes committed Aug 9, 2023
2 parents d69ba72 + 5281a39 commit bfe9ed8
Show file tree
Hide file tree
Showing 11 changed files with 473 additions and 145 deletions.
320 changes: 186 additions & 134 deletions cmake/cmake_celix/BundlePackaging.cmake

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,8 +384,8 @@ def requirements(self):
self.requires("libzip/[>=1.7.3 <2.0.0]")
self.options['libzip'].shared = True
if self.options.build_framework or self.options.build_pubsub:
self.requires("libuuid/1.0.3")
self.options['libuuid'].shared = True
self.requires("util-linux-libuuid/2.39")
self.options['util-linux-libuuid'].shared = True
if self.options.build_framework or self.options.build_celix_etcdlib:
self.requires("libcurl/[>=7.64.1 <8.0.0]")
self.options['libcurl'].shared = True
Expand Down
11 changes: 9 additions & 2 deletions misc/experimental/rust/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,16 @@ if (CELIX_RUST_EXPERIMENTAL)
)
FetchContent_MakeAvailable(Corrosion)

#Prepare a list of include paths needed to generating bindings for the Apache Celix C API
file(GENERATE
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/include_paths.txt"
CONTENT "$<TARGET_PROPERTY:framework,INTERFACE_INCLUDE_DIRECTORIES>;$<TARGET_PROPERTY:utils,INTERFACE_INCLUDE_DIRECTORIES>"
)

corrosion_import_crate(MANIFEST_PATH Cargo.toml)
corrosion_add_target_local_rustflags(rust_bundle_activator "-Cprefer-dynamic")

corrosion_add_target_local_rustflags(rust_bundle_activator "-Cprefer-dynamic")
corrosion_link_libraries(rust_bundle_activator Celix::framework)

#Note corrosion_import_crate import creates a rust_bundle_activator CMake target, but this is a INTERFACE target.
#Using the INTERFACE_LINK_LIBRARIES property we can get the actual target.
Expand All @@ -41,5 +49,4 @@ if (CELIX_RUST_EXPERIMENTAL)
Celix::shell_tui
rust_bundle
)

endif ()
1 change: 1 addition & 0 deletions misc/experimental/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@

[workspace]
members = [
"celix_bindings",
"hello_world_activator",
]
23 changes: 23 additions & 0 deletions misc/experimental/rust/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,26 @@ and is not intended to be used in production.

Ideally Rust support is done by adding a Rust API for Apache Celix and use that API for Rust bundles, the current
implementation only shows that is possible to write a bundle in Rust that gets called by Apache Celix framework.

# Building

To build rust source the Corrosion cmake module is used. This module will be automatically downloaded when building
using `FetchContent_Declare`.

To actual build the rust source files both the rust compiler and cargo are required. For ubuntu this can be installed
using apt:
```bash
sudo apt install rustc cargo
```
It is possible to define C bindings in rust manually, but this is a lot of work and error prone. Rust has a tool called
bindgen which can generate C bindings from a C header file. This is used to generate the C bindings for Apache Celix.
bindgen is used in the build.rs of the rust package `celix_bindings`.

It is also possible to run bindgen manually, for example:
```bash
cargo install bindgen # install bindgen, only needed once
PATH=$PATH:$HOME/.cargo/bin # add cargo bin to path

cd misc/experimental/rust/celix_bindings
bindgen -o src/celix_bindings.rs celix_bindings.h -- -I<celix_framework_include_dir> -I<celix_utils_include_dir>
```
28 changes: 28 additions & 0 deletions misc/experimental/rust/celix_bindings/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

[package]
name = "celix_bindings"
version = "0.0.1"

[build-dependencies]
bindgen = "0.66.1"

[lib]
name = "celix_bindings"
path = "src/lib.rs"
crate-type = ["rlib"]
65 changes: 65 additions & 0 deletions misc/experimental/rust/celix_bindings/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

extern crate bindgen;

use std::error::Error;
use std::path::PathBuf;
use std::fs::File;
use std::io::{self, BufRead};
use std::env;

fn print_include_paths() -> Result<Vec<String>, Box<dyn Error>> {
let build_dir = PathBuf::from(env::var("CORROSION_BUILD_DIR").unwrap());
let include_path_file = build_dir.join("include_paths.txt");

//let include_path_file = Path::new("include_paths.txt");
let file = File::open(&include_path_file)?;
let reader = io::BufReader::new(file);
let mut include_paths = Vec::new();
let line = reader.lines().next().ok_or("Expected at least one line")??;
for path in line.split(';') {
include_paths.push(path.to_string());
}
Ok(include_paths)
}

fn main() {
println!("cargo:info=Start build.rs for celix_bindings");
let include_paths = print_include_paths().unwrap();

let mut builder = bindgen::Builder::default()
.header("src/celix_bindings.h");

// Add framework and utils include paths
for path in &include_paths {
builder = builder.clang_arg(format!("-I{}", path));
}

// Gen bindings
let bindings = builder
.generate()
.expect("Unable to generate bindings");


let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("celix_bindings.rs"))
.expect("Couldn't write Apache Celix bindings!");
}
32 changes: 32 additions & 0 deletions misc/experimental/rust/celix_bindings/src/celix_bindings.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

/**
* @file celix_bindings.h
* @brief A header files that includes all Apache Celix headers used to create bindings.
*/

#include "celix_errno.h"
#include "celix_properties.h"
#include "celix_filter.h"

#include "celix_bundle_context.h"
#include "celix_framework.h"
#include "celix_framework_factory.h"
#include "celix_framework_utils.h"
41 changes: 41 additions & 0 deletions misc/experimental/rust/celix_bindings/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

#[allow(non_camel_case_types, non_snake_case, non_upper_case_globals, dead_code)]
mod bindings {
include!(concat!(env!("OUT_DIR"), "/celix_bindings.rs"));
}
pub use bindings::*;

//Note C #defines (compile-time constants) are not all generated in the bindings.
pub const CELIX_SUCCESS: celix_status_t = 0;
pub const CELIX_BUNDLE_EXCEPTION: celix_status_t = 70001;

// Move to celix_api lib
pub mod celix {

#[warn(unused_imports)]
pub enum LogLevel {
Trace = ::bindings::celix_log_level_CELIX_LOG_LEVEL_TRACE as isize,
Debug = ::bindings::celix_log_level_CELIX_LOG_LEVEL_DEBUG as isize,
Info = ::bindings::celix_log_level_CELIX_LOG_LEVEL_INFO as isize,
Warn = ::bindings::celix_log_level_CELIX_LOG_LEVEL_WARNING as isize,
Error = ::bindings::celix_log_level_CELIX_LOG_LEVEL_ERROR as isize,
}
}
6 changes: 5 additions & 1 deletion misc/experimental/rust/hello_world_activator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@

[package]
name = "rust_bundle_activator"
version = "0.1.0"
version = "0.0.1"

[dependencies]
celix_bindings = { path = "../celix_bindings" }

[lib]
name = "rust_bundle_activator"
path = "src/lib.rs"
crate-type = ["cdylib"]
87 changes: 81 additions & 6 deletions misc/experimental/rust/hello_world_activator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,91 @@
* under the License.
*/

extern crate celix_bindings;

use std::error::Error;
use std::os::raw::c_void;
use std::ffi::CString;
use std::ffi::NulError;
use celix_bindings::*; //Add all Apache Celix C bindings to the namespace (i.e. celix_bundleContext_log, etc.)

struct RustBundle {
name: String,
ctx: *mut celix_bundle_context_t,
}

impl RustBundle {

unsafe fn new(name: String, ctx: *mut celix_bundle_context_t) -> Result<RustBundle, NulError> {
let result = RustBundle {
name,
ctx,
};
result.log_lifecycle("created")?;
Ok(result)
}

unsafe fn log_lifecycle(&self, event: &str) -> Result<(), NulError> {
let id = celix_bundleContext_getBundleId(self.ctx);
let c_string = CString::new(format!("Rust Bundle '{}' with id {} {}!", self.name, id, event))?;
celix_bundleContext_log(self.ctx, celix_log_level_CELIX_LOG_LEVEL_INFO, c_string.as_ptr());
Ok(())
}

unsafe fn start(&self) -> Result<(), NulError> {
self.log_lifecycle("started")
}

unsafe fn stop(&self) -> Result<(), NulError> {
self.log_lifecycle("stopped")
}
}

impl Drop for RustBundle {
fn drop(&mut self) {
unsafe {
let result = self.log_lifecycle("destroyed");
match result {
Ok(()) => (),
Err(e) => println!("Error while logging: {}", e),
}
}
}
}

#[no_mangle]
pub unsafe extern "C" fn celix_bundleActivator_create(ctx: *mut celix_bundle_context_t, data: *mut *mut c_void) -> celix_status_t {
let rust_bundle = RustBundle::new("Hello World".to_string(), ctx);
if rust_bundle.is_err() {
return CELIX_BUNDLE_EXCEPTION;
}
*data = Box::into_raw(Box::new(rust_bundle.unwrap())) as *mut c_void;
CELIX_SUCCESS
}

#[no_mangle]
pub unsafe extern "C" fn celix_bundleActivator_start(data: *mut c_void, _ctx: *mut celix_bundle_context_t) -> celix_status_t {
let rust_bundle = &*(data as *mut RustBundle);
let result = rust_bundle.start();
match result {
Ok(()) => CELIX_SUCCESS,
Err(_) => CELIX_BUNDLE_EXCEPTION,
}
}

#[no_mangle]
pub unsafe extern "C" fn celix_bundleActivator_start(_data: *mut c_void, _context: *mut c_void) -> i32 {
println!("Rust Bundle started!");
0
pub unsafe extern "C" fn celix_bundleActivator_stop(data: *mut c_void, _ctx: *mut celix_bundle_context_t) -> celix_status_t {
let rust_bundle = &*(data as *mut RustBundle);
let result = rust_bundle.stop();
match result {
Ok(()) => CELIX_SUCCESS,
Err(_) => CELIX_BUNDLE_EXCEPTION,
}
}

#[no_mangle]
pub unsafe extern "C" fn celix_bundleActivator_stop(_data: *mut c_void, _context: *mut c_void) -> i32 {
println!("Rust Bundle stopped!");
0
pub unsafe extern "C" fn celix_bundleActivator_destroy(data: *mut c_void, _ctx: *mut celix_bundle_context_t) -> celix_status_t {
let rust_bundle = Box::from_raw(data as *mut RustBundle);
drop(rust_bundle);
CELIX_SUCCESS
}

0 comments on commit bfe9ed8

Please sign in to comment.