Skip to content
This repository has been archived by the owner on Feb 8, 2022. It is now read-only.

translate helloworld.cc #18

Closed
5 of 7 tasks
ctaggart opened this issue Apr 23, 2017 · 13 comments · Fixed by #24 or #48
Closed
5 of 7 tasks

translate helloworld.cc #18

ctaggart opened this issue Apr 23, 2017 · 13 comments · Fixed by #24 or #48

Comments

@ctaggart
Copy link
Owner

ctaggart commented Apr 23, 2017

#include <octave/oct.h>

DEFUN_DLD (helloworld, args, nargout,
           "Hello World Help String")
{
  octave_stdout << "Hello World has "
                << args.length () << " input arguments and "
                << nargout << " output arguments.\n";

  return octave_value_list ();
}

2017-09-26 troubleshooting ideas

https://github.com/ctaggart/octh_examples/blob/master/src/lib.rs

  • mkoctfile on Linux and record gcc calls
  • create oct file using just gcc
  • get rid of macros and use separate functions
  • give status to Octave maintainers and seek help
  • find out if with the layout test failing 19 failed layout tests #23 7 layout tests failing on Linux #38 all bets are off
  • find out the use of octh::root::std::string is wrong
  • figure out how to gdb debug from Octave itself
@ctaggart
Copy link
Owner Author

ctaggart commented Apr 23, 2017

Looks like the exported function from helloworld.oct when compiled from helloworld.cc is Ghelloworld.

C:\Octave> $env:path="C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.10.25017\bin\HostX86\x86;$env:path"

C:\Octave> dumpbin /exports helloworld.oct
Microsoft (R) COFF/PE Dumper Version 14.10.25019.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file helloworld.oct

File Type: DLL

  Section contains the following exports for helloworld.oct

    00000000 characteristics
    58F53BC4 time date stamp Mon Apr 17 17:03:48 2017
        0.00 version
           1 ordinal base
          23 number of functions
          23 number of names

    ordinal hint RVA      name

          1    0 00001570 Ghelloworld
          2    1 00001440 _Z11FhelloworldRK17octave_value_listi
          3    2 00017200 _ZN10dim_vectorD1Ev = _ZN9__gnu_cxx13stdio_filebufIwSt11char_traitsIwEEC1EiSt13_Ios_Openmodey
          4    3 000174F0 _ZN12octave_value16fast_elem_insertEiRKS_
          5    4 00017580 _ZN13string_vectorD0Ev = _ZN9__gnu_cxx13stdio_filebufIwSt11char_traitsIwEED2Ev
          6    5 000176A0 _ZN13string_vectorD1Ev
          7    6 000177D0 _ZN17octave_base_value12unique_cloneEv
          8    7 000177E0 _ZN5ArrayI12octave_valueED0Ev
          9    8 000178D0 _ZN5ArrayI12octave_valueED1Ev
         10    9 000179B0 _ZN5ArrayISsED0Ev
         11    A 00017AD0 _ZN5ArrayISsED1Ev = _ZN9__gnu_cxx18stdio_sync_filebufIcSt11char_traitsIcEED1Ev
         12    B 000845C0 _ZTI12octave_value
         13    C 000845D0 _ZTI13string_vector
         14    D 000845F0 _ZTI5ArrayI12octave_valueE
         15    E 00084600 _ZTI5ArrayISsE
         16    F 000856F0 _ZTS12octave_value
         17   10 00085700 _ZTS13string_vector
         18   11 00085710 _ZTS5ArrayI12octave_valueE
         19   12 00085730 _ZTS5ArrayISsE
         20   13 00086E60 _ZTV12octave_value
         21   14 00086E80 _ZTV13string_vector
         22   15 00086EC0 _ZTV5ArrayI12octave_valueE
         23   16 00086F00 _ZTV5ArrayISsE

@ctaggart
Copy link
Owner Author

So it looks like the Ghelloworld is the "installer function".

From C:\Octave\Octave-4.2.1\include\octave-4.2.1\octave\defun-int.h

#  define DEFINE_FUN_INSTALLER_FUN(name, doc)                   \
  DEFINE_FUNX_INSTALLER_FUN(#name, F ## name, G ## name, doc)
#endif

#define DEFINE_FUNX_INSTALLER_FUN(name, fname, gname, doc)              \
  extern "C"                                                            \
  OCTAVE_EXPORT                                                         \
  octave_function *                                                     \
  gname (const octave::dynamic_library& shl, bool relative)             \
  {                                                                     \
    check_version (OCTAVE_API_VERSION, name);                           \
                                                                        \
    octave_dld_function *fcn                                            \
      = octave_dld_function::create (fname, shl, name, doc);            \
                                                                        \
    if (relative)                                                       \
      fcn->mark_relative ();                                            \
                                                                        \
    return fcn;                                                         \
  }

@ctaggart
Copy link
Owner Author

The related sections of lib.rs:

    pub struct octave_function {
        pub _bindgen_opaque_blob: [u64; 7usize],
    }

    pub struct octave_dld_function {
        pub _bindgen_opaque_blob: [u64; 14usize],
    }

    extern "C" {
        #[link_name =
              "_ZN19octave_dld_function6createEPF17octave_value_listRKS0_iERKN6octave15dynamic_libraryERKSsSA_"]
        pub fn octave_dld_function_create(ff: root::octave_builtin_fcn,
                                          shl:
                                              *const root::octave::dynamic_library,
                                          nm: *const root::std::string,
                                          ds: *const root::std::string)
         -> *mut root::octave_dld_function;
    }

    impl octave_dld_function {
        #[inline]
        pub unsafe fn create(ff: root::octave_builtin_fcn,
                             shl: *const root::octave::dynamic_library,
                             nm: *const root::std::string,
                             ds: *const root::std::string)
         -> *mut root::octave_dld_function {
            octave_dld_function_create(ff, shl, nm, ds)
        }
        #[inline]
        pub unsafe fn register_type() { octave_dld_function_register_type() }
        #[inline]
        pub unsafe fn new(ff: root::octave_builtin_fcn,
                          shl: *const root::octave::dynamic_library,
                          nm: *const root::std::string,
                          ds: *const root::std::string) -> Self {
            let mut __bindgen_tmp = ::std::mem::uninitialized();
            octave_dld_function_octave_dld_function(&mut __bindgen_tmp, ff,
                                                    shl, nm, ds);
            __bindgen_tmp
        }
    }

@ctaggart
Copy link
Owner Author

ctaggart commented May 18, 2017

I'm currently running into this error and I'm not sure how to troubleshoot:

C:\Users\camer\rs\octh_helloworld [master +5 ~0 -0 !]> cargo build
   Compiling winapi v0.2.8
   Compiling libc v0.2.22
   Compiling unicode-segmentation v1.2.0
   Compiling libloading v0.4.0
   Compiling syntex_pos v0.58.1
   Compiling clang-sys v0.18.0
   Compiling kernel32-sys v0.2.2
   Compiling vec_map v0.8.0
error: failed to run custom build command for `kernel32-sys v0.2.2`
process didn't exit successfully: `C:\Users\camer\rs\octh_helloworld\target\debug\build\kernel32-sys-d715e52d58016295\b
uild-script-build` (exit code: 3221225781)
Build failed, waiting for other jobs to finish...
error: build failed

@ctaggart
Copy link
Owner Author

ctaggart commented May 22, 2017

I tried again this past weekend to translate the simple example. I made progress. I'm able to compile with the rustup nightly-x86_64-pc-windows-gnu installed. That is until I try to create a new octave_value_list. I can't find the empty constructor. It looks like there are a few overloads in https://github.com/NexMirror/Octave/blob/master/libinterp/octave-value/ovl.h, but I can't find then in https://raw.githubusercontent.com/ctaggart/octh/master/src/lib.rs.

Current code for octh_helloworld\src\lib.rs:

#![allow(non_snake_case)]
#![allow(unused_variables)]

extern crate octh;

use std::ffi::CString;

// https://thefullsnack.com/en/string-ffi-rust.html

#[no_mangle]
pub unsafe extern "C"  fn Ghelloworld (shl: *const octh::root::octave::dynamic_library, relative: bool) -> *mut octh::root::octave_dld_function {

    let fname = CString::new("Fhelloworld").unwrap();
    let pfname = fname.as_ptr() as octh::root::octave_builtin_fcn;
    std::mem::forget(pfname);

    let name = CString::new("helloworld").unwrap();
    let pname = name.as_ptr() as *const octh::root::std::string;
    std::mem::forget(pname);

    let doc = CString::new("Hello World Help String").unwrap();
    let pdoc = doc.as_ptr() as *const octh::root::std::string;
    std::mem::forget(pdoc);

    let fcn = octh::root::octave_dld_function_create(pfname, shl, pname, pdoc);

//    if relative {
//        fcn.mark_relative();
//    }
    return fcn;
}    

pub unsafe extern "C"  fn Fhelloworld (args: *const octh::root::octave_value_list, nargout: i32) -> octh::root::octave_value_list {
    let out = octh::root::octave_value_list::new();
    return out;
}

Code for octh_helloworld\build.rs:

fn main () {
    println!("cargo:rustc-link-search={}", "C:\\Octave\\OCTAVE~1.1\\lib\\octave\\4.2.1");
    println!("cargo:rustc-link-lib={}", "octave");
    println!("cargo:rustc-link-lib={}", "octinterp");
}

Current error:

C:\Users\camer\rs\octh_helloworld>cargo build
   Compiling octh_helloworld v0.1.0 (file:///C:/Users/camer/rs/octh_helloworld)
error[E0061]: this function takes 1 parameter but 0 parameters were supplied
  --> src\lib.rs:38:15
   |
38 |     let out = octh::root::octave_value_list::new();
   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 parameter

@ctaggart
Copy link
Owner Author

ctaggart commented May 24, 2017

I exposed an octave_value_list_create function via C++ in #20. The helloworld code is now here: https://github.com/ctaggart/octh_examples. It compiles, but does not link.

I think the current problem has something to do with libstdc++.a. I'm not sure if it is because it is found first in the rustup toolchain instead of Octave:

  1. "-L" "C:\Users\camer\.rustup\toolchains\nightly-x86_64-pc-windows-gnu\lib\rustlib\x86_64-pc-windows-gnu\lib"
  2. "-L" "C:\Octave\Octave-4.2.1\lib64\gcc\x86_64-w64-mingw32\4.9.4"

The full build log that is failing as well as the C++ one from Octave are in this gist:
https://gist.github.com/ctaggart/0a2676c24844890c161d6e5720a6b91f

@ctaggart
Copy link
Owner Author

ctaggart commented Jun 4, 2017

I'm not receiving the pthread link errors anymore, but I'm still getting link errors:


          C:\Users\camer\AppData\Local\Temp\rustc.Hk7dvrSKrazQ\libocth-caff0ea2aef87dc7.rlib(octhc.o): In function `dim_vector::dim_vector()':
          C:/Octave/Octave-4.2.1/include/octave-4.2.1/octave/dim-vector.h:261: undefined reference to `dim_vector::nil_rep()'
          C:\Users\camer\AppData\Local\Temp\rustc.Hk7dvrSKrazQ\libocth-caff0ea2aef87dc7.rlib(octhc.o): In function `Array<std::string>::Array()':

          C:/Octave/Octave-4.2.1/include/octave-4.2.1/octave/Array.h:253: undefined reference to `Array<std::string>::nil_rep()'

          C:\Users\camer\AppData\Local\Temp\rustc.Hk7dvrSKrazQ\libocth-caff0ea2aef87dc7.rlib(octhc.o): In function `Array<octave_value>::Array()':

          C:/Octave/Octave-4.2.1/include/octave-4.2.1/octave/Array.h:253: undefined reference to `Array<octave_value>::nil_rep()'


          C:\Users\camer\AppData\Local\Temp\rustc.Hk7dvrSKrazQ\libocth-caff0ea2aef87dc7.rlib(octhc.o):octhc.cc:(.rdata$_ZTV5ArrayI12octave_valueE[_ZTV5ArrayI12octave_valueE]+0x20): 
undefined reference to `Array<octave_value>::resize_fill_value() const'

          C:\Users\camer\AppData\Local\Temp\rustc.Hk7dvrSKrazQ\libocth-caff0ea2aef87dc7.rlib(octhc.o):octhc.cc:(.rdata$_ZTV13string_vector[_ZTV13string_vector]+0x20): undefined 
reference to `Array<std::string>::resize_fill_value() const'

          C:\Users\camer\AppData\Local\Temp\rustc.Hk7dvrSKrazQ\libocth-caff0ea2aef87dc7.rlib(octhc.o):octhc.cc:(.rdata$_ZTV5ArrayISsE[_ZTV5ArrayISsE]+0x20): undefined reference to 
`Array<std::string>::resize_fill_value() const'


          collect2.exe: error: ld returned 1 exit status

The errors appears to be related to the octch.o, which is the C++ code using the gcc crate.

I was able make the ld linker be verbose when run from Octave:
build.m:

mkoctfile "-Wl,--verbose" helloworld.cc

build.ps1:

C:\Octave\Octave-4.2.1\bin\octave-cli.exe build.m > build.txt

build.txt

I'd like to have the same verbose ld output from Rust, but nothing I've tried has worked.

@fitzgen
Copy link

fitzgen commented Jun 7, 2017

Where are Array<std::string>::resize_fill_value() const et al supposed to be defined? And are you sure they aren't inline functions, which would not have a symbol that can be linked against (in which case bindgen shouldn't be generating bindings to them, but older libclang doesn't give us a way to tell if a function is inlined or not)?

@ctaggart
Copy link
Owner Author

I got what I thought should be a helloworld compiling on Linux, but I get an unexpected Octave error when trying to load and run it. ctaggart/octh_examples#2

ctaggart added a commit that referenced this issue Sep 25, 2017
* add helloworld as an integration test #18

* helloworld moved over to  octh_examples repo
@ctaggart ctaggart reopened this Sep 25, 2017
@ctaggart
Copy link
Owner Author

It is 2 years later and Octave 5.1.0 is the current version. I'm back on Windows and I'm taking an online machine learning course that uses Octave, so I'm picking this back up.

The helloworld.cc with the macros expanded:

#include <octave/oct.h>

extern octave_value_list Fhelloworld (const octave_value_list&, int);

extern "C" octave_function * Ghelloworld (const octave::dynamic_library& shl, bool relative) {
  check_version ("api-v53", "helloworld");
  octave_dld_function *fcn = octave_dld_function::create (Fhelloworld, shl, "helloworld", "Hello World Help String");
  if (relative) fcn->mark_relative ();
  return fcn;
}

octave_value_list Fhelloworld (const octave_value_list& args, int nargout)
{
  (octave::__stdout__ ()) << "Hello World has "
                << args.length () << " input arguments and "
                << nargout << " output arguments.\n";

  octave_value_list retval (nargout);
  for (int i = 0; i < nargout; i++)
    retval(i) = octave_value (Matrix ());

  return retval;
}

@ctaggart
Copy link
Owner Author

I was able to compile C++ code and rust code with the same toolchain. It worked with both the g++ from Octave and from msys2 mingw-w64-x86_64-gcc.

https://github.com/rust-lang/rust#building-on-windows
http://www.msys2.org/
http://repo.msys2.org/distrib/x86_64/msys2-x86_64-20190524.exe

pacman -S mingw-w64-x86_64-gcc
rustup target add x86_64-pc-windows-gnu
rustup default x86_64-pc-windows-gnu
$env:PATH="C:\Octave\Octave-5.1.0.0\mingw64\bin;$env:PATH"
$env:PATH="C:\msys64\mingw64\bin;$env:PATH"
cargo build

build.rs

extern crate bindgen;
extern crate cc;

fn main() {
    println!(r"cargo:rustc-link-search=C:\Octave\Octave-5.1.0.0\mingw64\bin");
    println!(r"cargo:rustc-link-lib=octave-7");
    println!(r"cargo:rustc-link-lib=octinterp-7");

    cc::Build::new()
        .cpp(true)
        .include("C:\\Octave\\Octave-5.1.0.0\\mingw64\\include\\octave-5.1.0")
        .file("helloworld.cc")
        .compile("helloworld");
}

Cargo.toml

[lib]
crate-type = ["dylib"]

[build-dependencies]
cc = "*"

@ctaggart
Copy link
Owner Author

It will be easier to just deal with numbers and not deal with stdout or string conversion. This is an add function that sums all input numbers and returns the sum to all output variables.

>> a,b,c=add(1,2,3,4)
a =  10
b =  10
c =  10
#include <octave/oct.h>

extern octave_value_list Fadd (const octave_value_list&, int);

extern "C" octave_function * Gadd (const octave::dynamic_library& shl, bool relative) {
  octave_dld_function *fcn = octave_dld_function::create (Fadd, shl, "add", "adds inputs and returns sum to all outputs");
  if (relative) fcn->mark_relative ();
  return fcn;
}

octave_value_list Fadd (const octave_value_list& args, int nargout)
{
  int nargin = args.length();
  octave_value_list retval(nargout);
  int sum = 0;
  for (int i = 0; i < nargin; i++)
    sum += args(i).int_value();
  for (int i = 0; i < nargout; i++)
    retval(i) = octave_value(sum);
  return retval;
}

@ctaggart
Copy link
Owner Author

I merged #30 and created https://github.com/ctaggart/octave-add, which is a project for the above code. It compiles! Octave also tried to load the extension, but crashes.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants