Giter Site home page Giter Site logo

rust-qt / ritual Goto Github PK

View Code? Open in Web Editor NEW
1.2K 30.0 49.0 3.44 MB

Use C++ libraries from Rust

License: Apache License 2.0

CMake 0.69% C 0.30% C++ 2.98% Rust 95.02% Shell 0.16% Python 0.51% Dockerfile 0.31% HTML 0.02% JavaScript 0.01% CSS 0.01%
qt rust rust-crate rust-generator cpp-bindings rust-bindings rituals crates qt-generator qt-crate cpp

ritual's Introduction

ritual

Build Status

ritual allows to use C++ libraries from Rust. It analyzes the C++ API of a library and generates a fully-featured crate that provides convenient (but still unsafe) access to this API.

The main motivation for this project is to provide access to Qt from Rust. Ritual provides large amount of automation, supports incremental runs, and implements compatible API evolution. This is mostly dictated by the huge size of API provided by Qt and significant API differences between Qt versions. However, ritual is designed to be universal and can also be used to easily create bindings for other C++ libraries.

More information is available on rust-qt.github.io:

License

This project is licensed under either of

at your option.

If you use Qt, you should also take into account Qt licensing.

Contributing

Contributions are always welcome! You can contribute in different ways:

  • Submit a bug report, a feature request, or an improvement suggestion at the issue tracker;
  • Write a test or an example for a Qt crate (porting examples from the official Qt documentation is a good option);
  • Pick up an issue with help wanted tag.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the project by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

ritual's People

Contributors

csnover avatar dant3 avatar davidedelpapa avatar er-vin avatar riateche avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ritual's Issues

Allocation place preference

Current state: class types can be allocated as Rust structs (AsStruct marker) or as boxed C++ pointers (AsBox). Allocation place can be selected by passing a marker as an argument to a method.

Planned changes:

Some types may have one of allocation places blocked (AsStruct because it's unsafe or AsBox because it's useless). These types don't accept the markers as arguments at all.

Most of other types should have a preferred allocation place. Default behavior can be accessed without a marker. For example, if AsBox method is preferred for a type, passing no marker results in AsBox placement, and passing AsStruct marker overrides it.

These preferences should be automatically detected based on C++ API. Lib spec should be able to override automatic detection for any type.

Build error: undefined reference to symbol 'glGetShaderiv'

From @o01eg on April 24, 2017 16:10

When I building test application I get link error:

error: linking with `x86_64-pc-linux-gnu-gcc` failed: exit code: 1
  |
  = note: "x86_64-pc-linux-gnu-gcc" "-Wl,--as-needed" "-Wl,-z,noexecstack" "-m64" "-L" "/usr/lib64/rust-9999/rustlib/x86_64-unknown-linux-gnu/lib" "/mnt/another/srcs/myHG/qt002/target/debug/deps/qt002-46ad6d4010520222.0.o" "-o" "/mnt/another/srcs/myHG/qt002/target/debug/deps/qt002-46ad6d4010520222" "-Wl,--gc-sections" "-pie" "-nodefaultlibs" "-L" "/mnt/another/srcs/myHG/qt002/target/debug/deps" "-L" "/mnt/another/srcs/myHG/qt002/target/debug/build/qt_gui-f784009b8344c408/out/c_lib/install/lib" "-L" "/usr/lib64" "-L" "/mnt/another/srcs/myHG/qt002/target/debug/build/qt_core-60553f7912947b5a/out/c_lib/install/lib" "-L" "/usr/lib64" "-L" "/usr/lib64/rust-9999/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,-Bstatic" "/mnt/another/srcs/myHG/qt002/target/debug/deps/libqt_gui-0d4794050bcbd5fd.rlib" "/mnt/another/srcs/myHG/qt002/target/debug/deps/libqt_core-e72c4c7f6eb15228.rlib" "/mnt/another/srcs/myHG/qt002/target/debug/deps/liblibc-40c5d4ad7fb59dec.rlib" "/mnt/another/srcs/myHG/qt002/target/debug/deps/libcpp_utils-68cd462a29803ccc.rlib" "/usr/lib64/rust-9999/rustlib/x86_64-unknown-linux-gnu/lib/libstd-d20ce135c9335301.rlib" "/usr/lib64/rust-9999/rustlib/x86_64-unknown-linux-gnu/lib/libpanic_unwind-1a4ba5e8beac4036.rlib" "/usr/lib64/rust-9999/rustlib/x86_64-unknown-linux-gnu/lib/libunwind-cd26f559271bb98f.rlib" "/usr/lib64/rust-9999/rustlib/x86_64-unknown-linux-gnu/lib/librand-3d8d915c03524d7b.rlib" "/usr/lib64/rust-9999/rustlib/x86_64-unknown-linux-gnu/lib/libcollections-a7d339664f02e769.rlib" "/usr/lib64/rust-9999/rustlib/x86_64-unknown-linux-gnu/lib/liballoc-183f71f93a02fda2.rlib" "/usr/lib64/rust-9999/rustlib/x86_64-unknown-linux-gnu/lib/liballoc_jemalloc-f435e8d4a74b9cdb.rlib" "/usr/lib64/rust-9999/rustlib/x86_64-unknown-linux-gnu/lib/liblibc-880e63ad7955cdee.rlib" "/usr/lib64/rust-9999/rustlib/x86_64-unknown-linux-gnu/lib/libstd_unicode-b5a39590f4af960b.rlib" "/usr/lib64/rust-9999/rustlib/x86_64-unknown-linux-gnu/lib/libcore-b03b2a5c061a4a4c.rlib" "/usr/lib64/rust-9999/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-47c52e4884184cf0.rlib" "-Wl,-Bdynamic" "-l" "Qt5Gui" "-l" "stdc++" "-l" "Qt5Core" "-l" "stdc++" "-l" "util" "-l" "dl" "-l" "rt" "-l" "pthread" "-l" "gcc_s" "-l" "pthread" "-l" "c" "-l" "m" "-l" "rt" "-l" "pthread" "-l" "util"
  = note: /usr/lib/gcc/x86_64-pc-linux-gnu/5.4.0/../../../../x86_64-pc-linux-gnu/bin/ld: /mnt/another/srcs/myHG/qt002/target/debug/deps/libqt_gui-0d4794050bcbd5fd.rlib(qt_gui_c_QOpenGLExtraFunctions.cpp.o): undefined reference to symbol 'glGetShaderiv'
          /usr/lib64/opengl/nvidia/lib/libGLESv2.so.2: error adding symbols: DSO missing from command line
          collect2: error: ld returned 1 exit status

If I add RUSTFLAGS="-l GL" it builds but I suppose it should add this flag from configuration step.

Copied from original issue: rust-qt/qt_gui#1

AsRef, AsMut, Borrow, Deref

Investigate if AsRef, AsMut, Borrow, Deref traits should be implemented to convert from &T1 to &T2 if T1 is a C++ subclass or T2.

Fix missing documentation uses

The generator can say which documentation entries were left unused. It currently generates too much noise, but it can be reduced.

  • Filter out tutorials (or at least anything that is not a valid identifier);
  • Filter out private fields (why are they even there?);
  • Check enum parsing.

JUCE

I'd love to see the JUCE library wrapped so it can be used from Rust.

Remove hardcoded compiler flags

Compiler flags should be specified by lib specs. Flags may depend on current OS or toolchain.

Compiler flags appear in these places:

  • cpp_parser - flags for clang parser;
  • cpp_code_generator - flags for C library;
  • templates/c_lib/CMakeLists.txt - more flags for C library.

Failure to parse methods with '*&' types

I get about 100 of these errors, usually of the form:

Failed to parse method: _CORBA_String_out::operator char *&
entity: Entity { kind: ConversionFunction, display_name: Some("operator char *&()"), location: Some(SourceLocation { file: File { path: "/usr/local/include/omniORB4/stringtypes.h" }, line: 526, column: 3, offset: 14679 }) }
error: Unknown type in conversion operator: 'char *&'

But also of the form:

Unable to produce C function for method:
CORBA::AbstractBase*& CORBA::AbstractBase_var::inout()
Error:Can't convert type to C: CppType { base: Class(CppTypeClassBase { name: "CORBA::AbstractBase", template_arguments: None }), indirection: PtrRef, is_const: false }: Unsupported level of indirection

It should be possible to parse these reference types into unsafe pointers in Rust.

Mobile platform support

Theoretically, mobile platform support (iOS, Android) would be nice, since both Qt and Rust support them on some level.

Mac OS: command line tools required

  • Write somewhere in the documentation that command line developer tools are required (see this).
  • Detect if the tools are not installed and show an error message.

Improve Qt documentation support

  • (+) Automatically find and import documentation if Qt distribution package is detected;
  • (+) Document a way to provide documentation data;
  • (+) Export description and detailed description for C++ enums and classes;
  • (+) Export description of enum variants.
  • (+) Don't show original C++ names of enum variants if none of the names were changed.
  • Make "C++ documentation" a link to the web site;
  • Replace <a> and <img> links with links to the web site;
  • If a C++ method or type is referenced in C++ documentation, append links to corresponding Rust methods after C++ documentation block.
  • Publish generated documentation and add a link to the readmes.

Remove ReturnType from overloading trait if not necessary

ReturnType accosiated type in an overloading trait allows a method to return values of different types depending on types of arguments. However, it causes unnecessary confusion about return type and should not be used if all variants return the same type.

Public class fields API

Generate const and mut getters for public class fields.

Export Qt documentation for fields.

Enum to int conversion

In C++, static_cast can convert any enums to int and back. Such conversions are used in many APIs, so we need to implement such conversion for all imported enums. Using From trait and transmuting to c_int should be enough.

Remove spec.json in favor of more powerful API for build scripts

Current state of lib specs for Qt contains a lot of repetition, and it would be better to generate it somewhat automatically instead of writing it manually. I intend to totally replace it with build scripts written in Rust code. The library's build script will have access to the generator's APIs for any configuring, blacklisting and custom processing it needs. Eventually all Qt-specific behavior will be moved out of cpp_to_rust into Qt-themed crates.

Building a library from cpp_to_rust's command line will no longer be possible. A new crate will be needed to wrap a new library. Ability to build crates independent of cpp_to_rust will persist, however.

Test on other platforms

Interesting options:

  • 32-bit Linux, Windows, and OSX;
  • Windows with MSVC toolchain other than 14 (VS 2015).

Setup CI for Qt crates

Now that cpp_to_rust runs on Linux, Mac OS and Windows with Travis and Appveyor, we need to setup the same process for Qt crates. They already have a build configuration for Linux, but it needs to be expanded.

Use gcc crate instead of cmake?

Right now cmake is required for building the lib generated by cpp_to_rust an alternative would be to use the gcc crate instead which would remove the need for the user to have cmake installed.

Detecting and removing name prefixes

Qt only have "Q" prefix, but other libraries or parts of libraries may have different prefixes. Rust's crate and module system makes prefixes useless, so we should remove them whenever possible. We should detect common prefixes in classes, functions and/or submodules within each generated module and remove them.

fatal error: 'stddef.h' file not found

From @jonas-schievink on January 28, 2017 20:6

I'm trying to write a crate that depends on qt_gui, but compilation of qt_core fails with an error that really shouldn't happen. I'm on x86-64 Arch Linux.

   Compiling qt_core v0.1.3
error: failed to run custom build command for `qt_core v0.1.3`
process didn't exit successfully: `/home/jonas/dev/qgui/target/debug/build/qt_core-d308c34030383918/build-script-build` (exit code: 1)
--- stdout
Detecting Qt directories...
Executing command: "qmake" "-query" "QT_INSTALL_HEADERS"
QT_INSTALL_HEADERS = "/usr/include/qt"
Executing command: "qmake" "-query" "QT_INSTALL_LIBS"
QT_INSTALL_LIBS = "/usr/lib"
Reading input Cargo.toml
Parsing C++ headers.
clang version 3.9.1 (tags/RELEASE_391/final)
Initializing clang...
clang arguments: ["-Xclang", "-detailed-preprocessing-record", "-fPIC", "-fcxx-exceptions", "-std=gnu++11", "-I", "/usr/include/qt", "-I", "/usr/include/qt/QtCore"]
Diagnostics:
/../lib64/gcc/x86_64-pc-linux-gnu/6.3.1/../../../../include/c++/6.3.1/cstddef:50:10: fatal error: 'stddef.h' file not found
Error:
   0: fatal clang error
   1: C++ parser failed

Output of clang++ -v:

clang version 3.9.1 (tags/RELEASE_391/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-pc-linux-gnu/6.3.1
Found candidate GCC installation: /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/6.3.1
Found candidate GCC installation: /usr/lib/gcc/x86_64-pc-linux-gnu/6.3.1
Found candidate GCC installation: /usr/lib64/gcc/x86_64-pc-linux-gnu/6.3.1
Selected GCC installation: /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/6.3.1
Candidate multilib: .;@m64
Selected multilib: .;@m64

Rust version: rustc 1.14.0 (e8a012324 2016-12-16)

Qt version seems to be 5.7.1.

Copied from original issue: rust-qt/qt_core#1

Exception/panic safety

Passing exceptions and panics through FFI boundary is forbidden. It's probably best to wrap all C++ calls to try/catch and all Rust lambda calls to catch_unwind, and terminate the process completely in case of an exception or a panic, but we need to test if there are any negative effects.

Failure in all type caption strategies for methods with multiple return values

The panic message is:

values dump: [CppMethodWithFfiSignature { cpp_method: CppMethod { name: "_nil", class_membership: Some(CppMethodClassMembership { class_type: CppTypeClassBase { name: "CORBA::_omni_AbstractBaseObjref", template_arguments: None }, kind: Regular, is_virtual: false, is_pure_virtual: false, is_const: false, is_static: true, visibility: Public, is_signal: false }), operator: None, return_type: CppType { base: Class(CppTypeClassBase { name: "CORBA::Object", template_arguments: None }), indirection: Ptr, is_const: false }, arguments: [], arguments_before_omitting: None, allows_variadic_arguments: false, include_file: "CORBA_AbstractBase.h", origin_location: None, template_arguments: None, declaration_code: None, inherited_from: Some(CppMethodInheritedFrom { doc_id: "CORBA::Object::_nil", declaration_code: Some("static _ptr_type _nil ( )"), short_text: "static CORBA::Object* CORBA::Object::_nil()", class_type: CppTypeClassBase { name: "CORBA::Object", template_arguments: None } }) }, allocation_place: NotApplicable, c_signature: CppFfiFunctionSignature { arguments: [], return_type: CppFfiType { original_type: CppType { base: Class(CppTypeClassBase { name: "CORBA::Object", template_arguments: None }), indirection: Ptr, is_const: false }, ffi_type: CppType { base: Class(CppTypeClassBase { name: "CORBA::Object", template_arguments: None }), indirection: Ptr, is_const: false }, conversion: NoChange } } }, CppMethodWithFfiSignature { cpp_method: CppMethod { name: "_nil", class_membership: Some(CppMethodClassMembership { class_type: CppTypeClassBase { name: "CORBA::_omni_AbstractBaseObjref", template_arguments: None }, kind: Regular, is_virtual: false, is_pure_virtual: false, is_const: false, is_static: true, visibility: Public, is_signal: false }), operator: None, return_type: CppType { base: Class(CppTypeClassBase { name: "CORBA::AbstractBase", template_arguments: None }), indirection: Ptr, is_const: false }, arguments: [], arguments_before_omitting: None, allows_variadic_arguments: false, include_file: "CORBA_AbstractBase.h", origin_location: None, template_arguments: None, declaration_code: None, inherited_from: Some(CppMethodInheritedFrom { doc_id: "CORBA::AbstractBase::_nil", declaration_code: Some("static _ptr_type _nil ( )"), short_text: "static CORBA::AbstractBase* CORBA::AbstractBase::_nil()", class_type: CppTypeClassBase { name: "CORBA::AbstractBase", template_arguments: None } }) }, allocation_place: NotApplicable, c_signature: CppFfiFunctionSignature { arguments: [], return_type: CppFfiType { original_type: CppType { base: Class(CppTypeClassBase { name: "CORBA::AbstractBase", template_arguments: None }), indirection: Ptr, is_const: false }, ffi_type: CppType { base: Class(CppTypeClassBase { name: "CORBA::AbstractBase", template_arguments: None }), indirection: Ptr, is_const: false }, conversion: NoChange } } }]

All type caption strategies have failed! Involved functions:
  static CORBA::Object* CORBA::_omni_AbstractBaseObjref::_nil()
  static CORBA::AbstractBase* CORBA::_omni_AbstractBaseObjref::_nil()
thread 'main' panicked at 'all type caption strategies have failed', src/cpp_ffi_generator.rs:212

I'm guessing the failure is due to the overloaded return type. This should be captionable if the argument types are.

Implement operator traits

Operators are currently exported as plain functions. We need to implement operator traits (Add, Sub, ...) instead.

Alternative tuple-less overloading strategy

Method overloading can be emulated without tuples, but the function can only have fixed number of arguments.

Example implementation:

trait Tr1 {
    type Ret;
    fn exec(self) -> Self::Ret;
}

fn func1<T1, T2, T3>(arg1: T1, arg2: T2, arg3: T3) -> <(T1, T2, T3) as Tr1>::Ret
    where (T1, T2, T3): Tr1
{
    Tr1::exec((arg1, arg2, arg3))
}

impl Tr1 for (i32, i32, i32) {
    type Ret = i32;
    fn exec(self) -> i32 {
        println!("exec1 {:?}", self);
        self.0
    }
}

impl Tr1 for (f32, f32, f32) {
    type Ret = f32;
    fn exec(self) -> f32 {
        println!("exec2 {:?}", self);
        self.0
    }
}

impl Tr1 for (f32, f32, ()) {
    type Ret = f32;
    fn exec(self) -> f32 {
        println!("exec3 {:?}", self);
        self.0
    }
}

fn main() {
    println!("{}", func1(1i32, 2i32, 3i32));
    println!("{}", func1(1.0f32, 2.0f32, 3.0f32));
    println!("{}", func1(1.0f32, 2.0f32, ()));
    // func1(1.0f32, 2i32, ()); - doesn't compile
}

Variants that have fewer than maximum number of arguments are filled with () up to maximum number. If there is a variant that needs more than 2 () items added, the generator should fall back to tuple-based strategy.

Subclassing API

Let's have a C++ class that can be subclassed:

class Example {
public:
  Example(int x);
  virtual ~Example();
  virtual int vfunc2(double y);
protected:
  void func1();
};

First, we create a C++ wrapper:

class ExampleSubclass : public Example {
  ExampleSubclass(int x);
  ~ExampleSubclass();
  void func1();
  int vfunc2(double y);

  void set_vfunc2_func(int (*func)(void*, double), void* data);
  void set_destructor_func(void (*func)(void*), void* data);
private:
  int (*m_func2_func)(void*, double);
  void* m_func2_data;

  void (*m_destructor_func)(void*);
  void* m_destructor_data;

};

ExampleSubclass::ExampleSubclass(int x) : Example(x) {
  m_func2_func = 0;
  m_func2_data = 0;
  m_destructor_func = 0;
  m_destructor_data = 0;
}

ExampleSubclass::~ExampleSubclass() {
  if (m_destructor_func) {
    m_destructor_func(m_destructor_data);
  }
}

void ExampleSubclass::func1() {
  return Example::func1();
}

void ExampleSubclass::set_vfunc2_func(int (*func)(void*, double), void* data) {
  m_func2_func = func;
  m_func2_data = data;
}

void ExampleSubclass::set_destructor_func(void (*func)(void*), void* data) {
  m_destructor_func = func;
  m_destructor_data = data;
}

int ExampleSubclass::vfunc2(double y) {
  if (m_func2_func) {
    return m_func2_func(m_func2_data, y);
  } else {
    return Example::vfunc2(y);
    // or abort() if the method was pure virtual
  }
}

The wrapper exposes all protected functions of the base class and reimplements all its virtual functions. It allows to add callbacks for each virtual method. If a callback is not set, it calls base class implementation, as if the method was not reimplemented. It also allows to add a destructor callback for cleanup purposes.

Rust API changes the order of operations. First, the user needs to assign virtual functions. Then the object can be created:

let x = ExampleSubclassBuilder::new();
x.bind_func2(|arg| arg as i32);
let object: CppBox<ExampleSubclass> = x.new(constructor_arg);

If not all pure virtual functions were bound, ExampleSubclassBuilder::new function will panic.

ExampleSubclassBuilder::new creates a Rust struct that owns all lambdas and ensures that they are not deleted until the object itself is deleted. The struct is kept in memory by calling mem::forget. The destructor callback is used to delete this struct when it's not needed anymore. If the base class's destructor is virtual, you can pass the ExampleSubclass object's ownership to the C++ library. When it delets the object, the Rust struct cleanup will still be done. If the base class's destructor is not virtual, the only correct way to release the resources is to let CppBox delete the object.

ExampleSubclass Rust type is just a wrapper for ExampleSubclass C++ class, similar to other class wrappers. It exposes all its public methods, thus providing access to protected methods of the base class. Callback setters are not exposed. ExampleSubclass will provide means to downcast it to Example base type, just as any other derived class.

Example of initialization of a Rust struct with a subclass field:

impl MyExampleSubclass {
  pub fn new(arg: i32) -> MyExampleSubclass {
    let mut obj = MyExampleSubclass {
      example: CppBox::null(),
      other_data: 42,
    };
    let subclass = ExampleSubclassBuilder::new();
    x.bind_func2(|arg| {
      // can capture `self` or its field in some form here
      arg as i32
    });
    obj.example = x.new(arg);
    obj
  }
}

Detect diamond inheritance more correctly

Current implementation just allows the most common case and blocks all other methods as inaccessible.

  • populate inheritance_chain for inherited methods that were explicitly redeclared;
  • detect the common base even if it's not the first class in the chain.

qt_generator generates uncompilable code with clang >= 3.9

I built qt-generator binary (I have to remove -fPIC flag and add -fms-compatibility-version=19 to fix
issue https://bugreports.qt.io/browse/QTCREATORBUG-15940 in executor.rs)
Then I generated core, gui, widgets and ui_tools libraries into project root and add them into Cargo.toml as:

[dependencies]
qt_core = { path = "qt_core"}
qt_gui = { path = "qt_gui"}
qt_widgets = { path = "qt_widgets"}
qt_ui_tools = { path = "qt_ui_tools"}

When I start to build project I get next error:

_build_tools)
   Compiling qt_ui_tools v0.1.5 (file:///D:/devel/qt-rust-test01/qt_ui_tools)
     Running `D:\devel\qt-rust-test01\target\debug\build\qt_ui_tools-76c560e3a1c
9030c\build-script-build`
   Compiling qt_gui v0.1.5 (file:///D:/devel/qt-rust-test01/qt_gui)
     Running `D:\devel\qt-rust-test01\target\debug\build\qt_gui-4cb0bd8ab8a54939
\build-script-build`
   Compiling qt_core v0.1.5 (file:///D:/devel/qt-rust-test01/qt_core)
     Running `rustc --crate-name qt_core qt_core\src\lib.rs --crate-type lib --e
mit=dep-info,link -C debuginfo=2 -C metadata=c487475031745cd9 -C extra-filename=
-c487475031745cd9 --out-dir D:\devel\qt-rust-test01\target\debug\deps -L depende
ncy=D:\devel\qt-rust-test01\target\debug\deps --extern cpp_utils=D:\devel\qt-rus
t-test01\target\debug\deps\libcpp_utils-b667ad60ea3500de.rlib --extern libc=D:\d
evel\qt-rust-test01\target\debug\deps\liblibc-026076ef8cc90032.rlib -L native=C:
/Qt/Qt5.6.2/5.6/msvc2015_64/lib -L native=D:\devel\qt-rust-test01\target\debug\b
uild\qt_core-ec07a1a733c9474e\out\c_lib_install\lib -l Qt5Core`
error: no associated item named `connect_static` found for type `object::Object`
 in the current scope
  --> qt_core\src\connections.rs:47:7
   |
47 |       ::object::Object::connect_static((self.object() as *const ::object::O
bject,
   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

error: Could not compile `qt_core`.

Caused by:
  process didn't exit successfully: `rustc --crate-name qt_core qt_core\src\lib.
rs --crate-type lib --emit=dep-info,link -C debuginfo=2 -C metadata=c48747503174
5cd9 -C extra-filename=-c487475031745cd9 --out-dir D:\devel\qt-rust-test01\targe
t\debug\deps -L dependency=D:\devel\qt-rust-test01\target\debug\deps --extern cp
p_utils=D:\devel\qt-rust-test01\target\debug\deps\libcpp_utils-b667ad60ea3500de.
rlib --extern libc=D:\devel\qt-rust-test01\target\debug\deps\liblibc-026076ef8cc
90032.rlib -L native=C:/Qt/Qt5.6.2/5.6/msvc2015_64/lib -L native=D:\devel\qt-rus
t-test01\target\debug\build\qt_core-ec07a1a733c9474e\out\c_lib_install\lib -l Qt
5Core` (exit code: 101)
Build failed, waiting for other jobs to finish...

Rust: rustc 1.17.0 (56124baa9 2017-04-24) (MSVC)
Cargo: cargo 0.18.0 (fe7b0cdcf 2017-04-24)
Clang: 4.0.0 Target: x86_64-pc-windows-msvc
Qt: 5.6.2
MSVC: 2017

Generated files: https://gist.github.com/o01eg/f09189548669594c263ed1ee5b823d47

cpp_to_rust revision: 0d4cd53

AsStruct and AsBox

Change generated API for methods that returns an object by value (including constructors):

  • Wrap raw pointers in CppBox because the caller always owns the returned object;
  • Rename allocation place markers to AsStruct and AsBox.

Automatically detect inaccessible methods by trying to compile them

Some methods are inaccessible even if they are declared in the library's header. The most common cases:

  1. A template method can use a method of a template type that may not be present, e.g. QVector<T>::contains will not compile if T does not have operator==.
  2. Template partial specialization can remove any methods for any template type, e.g. QFuture<void>::result is removed.
  3. A method can simply be left without implementation. Any attempt to use it will only fail on link stage with "undefined reference" error. In Qt, it's qt_check_for_QGADGET_macro method that is used only for template magic but has no implementation.

Currently the only way to fix it is to add all wrong methods to the blacklist in the lib spec. This is a very inconvenient way if there are a lot of methods.

Solution:

  1. Implement preliminary generation of small C++ projects for each method.
  2. Try to compile the projects and remove methods that don't compile.
  3. Add a lib spec field for a reference method that should always be available. This method will be tested before all others to check if the toolchain and environment are set up correctly for compiling.
  4. Drop the complicated code responsible for eliminating methods in favor of just testing if they compile. This may include complicated inheritance exceptions and abstract class constructors.

Template methods are currently not supported because they induce too many template instantiation errors. Automatic detection would allow to enable them.

Unsupported kind of type: ConstantArray

Dealing with C++ code that uses networking on OSX invariably includes headers like sys/_pthread/_pthread_types.h which are full of structs with constant array members. C++ objects with fields that are (eventually) composed of these structs fail to parse.

Rust supports fixed-length arrays, so this should be easy to add.

Improve self argument kind captions

Current suffixes: from_const (receives &self), from_mut (receives &mut self), static (static).

Better captions:

presence const member mut member static
all (no suffix) mut static
const member, mut member (no suffix) mut
const member, static (no suffix) static
mut member, static (no suffix) static

-fPIC unsupported by libclang on x86_64-pc-windows-msvc

From @o01eg on April 25, 2017 12:47

When I try to build Qt application on windows I get error:

   Compiling qt_core v0.1.3
     Running `rustc --crate-name build_script_build C:\Users\oleg_schelicalnov\.cargo\registry\src\github.com-1ecc6299db9ec823\qt_core-0.1.3\build.rs --crate-ty
pe bin --emit=dep-info,link -C debuginfo=2 -C metadata=923e9cfe594fc924 -C extra-filename=-923e9cfe594fc924 --out-dir D:\devel\qt002\target\debug\build\qt_core-
923e9cfe594fc924 -L dependency=D:\devel\qt002\target\debug\deps --extern qt_build_tools=D:\devel\qt002\target\debug\deps\libqt_build_tools-f3c031262549d90b.rlib
 --extern cpp_to_rust=D:\devel\qt002\target\debug\deps\libcpp_to_rust-6620496cc6f44dbc.rlib --cap-lints allow -L D:\devel\sqlite -L "C:\Program Files\LLVM\bin"
-L "C:\Program Files\LLVM\lib"`
     Running `D:\devel\qt002\target\debug\build\qt_core-923e9cfe594fc924\build-script-build`
error: failed to run custom build command for `qt_core v0.1.3`
process didn't exit successfully: `D:\devel\qt002\target\debug\build\qt_core-923e9cfe594fc924\build-script-build` (exit code: 1)
--- stdout
←[32mDetecting Qt directories...←[0m
←[32mExecuting command: "qmake" "-query" "QT_INSTALL_HEADERS"←[0m
←[32mQT_INSTALL_HEADERS = "D:/devel/Qt/Qt5.8.0/5.8/msvc2015_64/include"←[0m
←[32mExecuting command: "qmake" "-query" "QT_INSTALL_LIBS"←[0m
←[32mQT_INSTALL_LIBS = "D:/devel/Qt/Qt5.8.0/5.8/msvc2015_64/lib"←[0m
←[32mReading input Cargo.toml←[0m
←[32mParsing C++ headers.←[0m
←[32mclang version 4.0.0 (tags/RELEASE_400/final)←[0m
←[32mInitializing clang...←[0m
←[32mclang arguments: ["-Xclang", "-detailed-preprocessing-record", "-fPIC", "-fcxx-exceptions", "-std=c++14", "-I", "D:/devel/Qt/Qt5.8.0/5.8/msvc2015_64/includ
e", "-I", "D:/devel/Qt/Qt5.8.0/5.8/msvc2015_64/include\\QtCore"]←[0m
←[35mDiagnostics:←[0m
←[35merror: unsupported option '-fPIC' for target 'x86_64-pc-windows-msvc'←[0m
←[35mD:/devel/Qt/Qt5.8.0/5.8/msvc2015_64/include\QtCore/qnamespace.h:107:9: warning: enumerator value is not representable in the underlying type 'int' [-Wmicro
soft-enum-value]←[0m
←[35mD:/devel/Qt/Qt5.8.0/5.8/msvc2015_64/include\QtCore/qnamespace.h:163:9: warning: enumerator value is not representable in the underlying type 'int' [-Wmicro
soft-enum-value]←[0m
←[35mD:/devel/Qt/Qt5.8.0/5.8/msvc2015_64/include\QtCore/qnamespace.h:304:9: warning: enumerator value is not representable in the underlying type 'int' [-Wmicro
soft-enum-value]←[0m
←[35mD:/devel/Qt/Qt5.8.0/5.8/msvc2015_64/include\QtCore/qnamespace.h:1343:9: warning: enumerator value is not representable in the underlying type 'int' [-Wmicr
osoft-enum-value]←[0m
←[35mD:/devel/Qt/Qt5.8.0/5.8/msvc2015_64/include\QtCore/qnamespace.h:1346:9: warning: enumerator value is not representable in the underlying type 'int' [-Wmicr
osoft-enum-value]←[0m
←[35mD:/devel/Qt/Qt5.8.0/5.8/msvc2015_64/include\QtCore/qnamespace.h:1377:9: warning: enumerator value is not representable in the underlying type 'int' [-Wmicr
osoft-enum-value]←[0m
←[35mD:/devel/Qt/Qt5.8.0/5.8/msvc2015_64/include\QtCore/qnamespace.h:1594:9: warning: enumerator value is not representable in the underlying type 'int' [-Wmicr
osoft-enum-value]←[0m
←[35mD:/devel/Qt/Qt5.8.0/5.8/msvc2015_64/include\QtCore/qvariant.h:196:9: warning: enumerator value is not representable in the underlying type 'int' [-Wmicroso
ft-enum-value]←[0m
←[35mD:/devel/Qt/Qt5.8.0/5.8/msvc2015_64/include\QtCore/qtextcodec.h:89:9: warning: enumerator value is not representable in the underlying type 'int' [-Wmicros
oft-enum-value]←[0m
←[31mError:←[0m
←[31m   0: fatal clang error←[0m
←[31m   1: C++ parser failed←[0m

rust version:

rustc 1.16.0 (30cf806ef 2017-03-10)
binary: rustc
commit-hash: 30cf806ef8881c41821fbd43e5cf3699c5290c16
commit-date: 2017-03-10
host: x86_64-pc-windows-msvc
release: 1.16.0
LLVM version: 3.9

clang version:

clang version 4.0.0 (tags/RELEASE_400/final)
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: C:\Program Files\LLVM\bin

Copied from original issue: rust-qt/qt_core#2

Platform independence

Right now the Qt libs becomes platform dependent depending on where it was compiled.

qt.rs over here https://github.com/kitech/qt.rs/blob/master/src/gui/qcolor.rs#L570 solves it this way

  // proto:  void QColor::QColor(const char * name);
impl<'a> /*trait*/ QColor_new for (&'a  String) {
  fn new(self) -> QColor {
    // let qthis: *mut c_void = unsafe{calloc(1, 32)};
    // unsafe{_ZN6QColorC2EPKc()};
    let ctysz: c_int = unsafe{QColor_Class_Size()};
    let qthis_ph: u64 = unsafe{calloc(1, ctysz as usize)} as u64;
    let arg0 = self.as_ptr()  as *mut c_char;
    let qthis: u64 = unsafe {C_ZN6QColorC2EPKc(arg0)};
    let rsthis = QColor{qclsinst: qthis, ..Default::default()};
    return rsthis;
    // return 1;
  }
}

By having generated a function that returns a size of the object (which is in the FFI code including the C++ headers) and here doing a calloca here to allocate zeroed memory.

Of course the backside of this approach is that when using objects like this they now need to be allocated on the heap which adds run-time overhead.

Not sure if this is something worth investigating or not.

Problems generating code with pure virtual methods

When generating code for qt_gui

qt/cpp_to_rust/gui/c_lib/source/src/qt_gui_c_QSyntaxHighlighter.cpp:4:15: error: allocating an object of abstract class type 'QSyntaxHighlighter'
  new(output) QSyntaxHighlighter(parent);

This is when generating code for Qt 5.7 on Mac (using the travis branch)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.