rust-qt / ritual Goto Github PK
View Code? Open in Web Editor NEWUse C++ libraries from Rust
License: Apache License 2.0
Use C++ libraries from Rust
License: Apache License 2.0
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
I just heard about this https://github.com/therecipe/qt I'm not sure if it's something that well help the Rust bindings but there might be some cross over between the projects.
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 |
Some methods are inaccessible even if they are declared in the library's header. The most common cases:
QVector<T>::contains
will not compile if T
does not have operator==
.QFuture<void>::result
is removed.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:
Template methods are currently not supported because they induce too many template instantiation errors. Automatic detection would allow to enable them.
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.
I'd love to see the JUCE library wrapped so it can be used from Rust.
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.
If something in a pure virtual method can't be parsed, the class should still be marked as abstract.
Allow to specify relative paths in lib spec.
Running with cargo run
, I get this panic message, even in release
profile. Mysteriously unhelpful panics in release builds are one of the reasons I avoid panic!
and unwrap
at all costs. What file or directory is it looking for?
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.(part of #7)
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.
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.
cpp_to_rust panics and dies right after printing "Parsing methods...". The stack trace begins in cpp_to_rust::cpp_parser::CppParser::parse_canonical_type
, but I'm not sure where. Unfortunately unwrap()
is called several times within that function.
Maybe generated API methods should be more permissive about accepted argument types.
If a dependency is missing (no -d
option or no build dependency in Cargo.toml), the generator should report the issue.
Investigate if AsRef, AsMut, Borrow, Deref traits should be implemented to convert from &T1
to &T2
if T1
is a C++ subclass or T2
.
QObject
subclasses can have custom properties, but I'm not sure it needs to be doable from Rust.
The generator can say which documentation entries were left unused. It currently generates too much noise, but it can be reduced.
Operators are currently exported as plain functions. We need to implement operator traits (Add
, Sub
, ...) instead.
<a>
and <img>
links with links to the web site;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.
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
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.
Change generated API for methods that returns an object by value (including constructors):
CppBox
because the caller always owns the returned object;AsStruct
and AsBox
.I wonder if you have thought about how this would work? I was pointed to this on the users forum
https://github.com/White-Oak/qml-rust/blob/master/examples/qobjects.rs#L16
https://github.com/White-Oak/qml-rust/blob/master/src/macros.rs#L90
It seems fairly complex but I'm not sure how QObject works in details. Regardless slots & signals are a pretty big part of working with Qt so I wonder if you have any ideas of how this could be implemented?
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.
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
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
Interesting options:
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)
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.
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.
Current implementation requires that include files of the library should be in a separate folder. Some libraries can have only one or several include files, and they can be installed in the system folder along with other include files.
add_inherited_methods
and inherited_methods_from
take a lot of time.
Generate const and mut getters for public class fields.
Export Qt documentation for fields.
Current implementation just allows the most common case and blocks all other methods as inaccessible.
inheritance_chain
for inherited methods that were explicitly redeclared;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.
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.
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.
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.
new_uninitialized
methods of structs is an implementation detail and should be hidden.
Wrap qobject_cast
similar to dynamic_cast
.
Theoretically, mobile platform support (iOS, Android) would be nice, since both Qt and Rust support them on some level.
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
}
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.