This is an automated email from the ASF dual-hosted git repository.
kou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/main by this push:
new 9009dd76e4 GH-33854: [MATLAB] Add basic libmexclass integration code
to MATLAB interface (#34563)
9009dd76e4 is described below
commit 9009dd76e4e9a2f4f13340ebf4173e71813b359b
Author: Kevin Gurney <[email protected]>
AuthorDate: Mon Apr 24 21:26:36 2023 -0400
GH-33854: [MATLAB] Add basic libmexclass integration code to MATLAB
interface (#34563)
### Rationale for this change
This pull request is a follow up to [this mailing list
discussion](https://lists.apache.org/thread/2kgxbs54dw4wvcwrthzvb1ljqcvnrv7h)
about integrating
[`mathworks/libmexclass`](https://github.com/mathworks/libmexclass/) with the
MATLAB Interface to Arrow code base.
We've spent the last few months working on building `libmexclass` from
scratch in order to ease development of the MATLAB Interface to Arrow.
`libmexclass` essentially provides a way to connect MATLAB classes with
corresponding C++ classes using an approach inspired by the [Proxy Design
Pattern](https://en.wikipedia.org/wiki/Proxy_pattern).
Our hope is that using `libmexclass` will enable us to more easily build
out an object-oriented MATLAB Interface to Arrow memory by wrapping
corresponding Arrow C++ classes and "proxying" method calls on these MATLAB
objects to the underlying Arrow C++ objects.
### What changes are included in this PR?
1. Modifications were made to the CMake build system for the MATLAB
interface to use `libmexclass` under the hood. This includes the addition of a
new build flag `-D MATLAB_ARROW_INTERFACE = ON | OFF` which toggles building
the new code that uses `libmexclass` under the hood.
2. To illustrate the basic usage of `libmexclass`, we have added one new
MATLAB class `arrow.array.Float64Array`. This class allows users to construct
an Arrow array with logical type `Float64` from a MATLAB `double` array with
zero data copies. Under the hood, a `Proxy` wraps and bounds the lifetime of
the underlying Arrow C++ `Float64Array` object. In addition, this `Proxy` is
responsible for delegating method calls on an `arrow.array.Float64Array` to the
corresponding Arrow C++ `Fl [...]
### Are these changes tested?
Yes, these changes have been tested on Linux, macOS, and Windows.
1. We've modified the MATLAB CI GitHub Actions workflow
(`.github/workflows/matlab.yml`) to build the new `arrow.array.Float64Array`
code using `libmexclass`. This includes passing `-D MATLAB_ARROW_INTERFACE=ON`
to the `cmake` command call in `ci/scripts/matlab_build.sh`.
2. We've added a new basic MATLAB test `test/arrow/array/tFloat64Array.m`
which tests for successful construction of an `arrow.array.Float64Array`. This
[test is passing successfully in the MATLAB CI
workflow](https://github.com/mathworks/arrow/actions/runs/4419365852/jobs/7747694543#step:6:50).
3. We've confirmed that the [`Dev` CI workflow linting checks are all
passing](https://github.com/mathworks/arrow/actions/runs/4419365845) and
appropriate Apache license headers have been added.
4. We've manually tested creation, deletion, and assignment of multiple
`arrow.array.Float64Array` instances on Linux, macOS, and Windows with a
variety of different MATLAB `double` arrays.
### Are there any user-facing changes?
Yes, there is now a public class named `arrow.array.Float64Array` which is
added to the MATLAB Path.
Included below is a simple example of creating two different
`arrow.array.Float64Array` objects in MATLAB:
```matlab
>> A = arrow.array.Float64Array([1, 2, 3])
A =
[
1,
2,
3
]
>> random = arrow.array.Float64Array(rand(1, 10, 100))
random =
[
0.6311887342690112,
0.355073651878849,
0.9970032716066477,
0.22417149898312716,
0.6524510729686149,
0.6049906419082594,
0.38724543148313495,
0.14218715929050407,
0.025134985710203117,
0.4211122537652413,
...
0.6228027906591304,
0.7966246853083961,
0.74587490154065,
0.12553623135481973,
0.8223940067590204,
0.02515050142850217,
0.41442888092403163,
0.7314074679729372,
0.7813740002759628,
0.367285915131369
]
```
**Note**: This is an early stage PR, so the naming scheme
`arrow.array.<Type>Array` might change in the future.
### Future Directions
1. Currently, the "old" `featherread`/`featherwrite` code is still being
built by CMake and installed to the specified `CMAKE_INSTALL_PREFIX`. This
slows down the build process and complicates the build system logic. In
addition, these Feather functions only support reading and writing a subset of
Feather V1 files. We should considering disabling building of this legacy code
by default or removing it entirely. In the long term, when we have more Arrow
types in MATLAB (e.g. `arrow.Tabl [...]
2. We would like to start adding more numeric array classes like
(`arrow.array.UInt8Array`, `arrow.array.Int64Array`, etc.).
3. We only added one very basic test for `arrow.array.Float64Array` in this
pull request. We should add a lot more tests as the APIs develop to test things
like indexing, copying, slicing, etc.
4. We don't have any documentation for `arrow.array.Float64Array` right
now. In general, we should start adding detailed documentation for the new APIs
as we start to implement them.
5. Lots more! This is just the beginning of building out the MATLAB
Interface to Arrow APIs. We plan on creating GitHub issues for tracking work as
we go.
### Notes
1. Creating `libmexclass` and integrating it with the Arrow code base was a
team effort! Thank you to @ sreeharihegden, @ lafiona, @ sgilmore10, @
jhughes-mw, and others at @ MathWorks for their help with this pull request!
2. Closes: #33854
Lead-authored-by: Kevin Gurney <[email protected]>
Co-authored-by: Fiona La <[email protected]>
Co-authored-by: shegden <[email protected]>
Co-authored-by: Sreehari Hegden <[email protected]>
Co-authored-by: Fiona la <[email protected]>
Signed-off-by: Sutou Kouhei <[email protected]>
---
ci/scripts/matlab_build.sh | 9 +-
matlab/CMakeLists.txt | 183 +++++++++++++--------
.../cpp/arrow/matlab/array/proxy/float64_array.cc | 25 +++
.../cpp/arrow/matlab/array/proxy/float64_array.h | 60 +++++++
matlab/src/cpp/arrow/matlab/mex/gateway.cc | 30 ++++
matlab/src/cpp/arrow/matlab/proxy/factory.cc | 36 ++++
matlab/src/cpp/arrow/matlab/proxy/factory.h | 32 ++++
matlab/src/matlab/+arrow/+array/Float64Array.m | 44 +++++
matlab/test/arrow/array/tFloat64Array.m | 41 +++++
matlab/tools/cmake/BuildMatlabArrowInterface.cmake | 108 ++++++++++++
10 files changed, 500 insertions(+), 68 deletions(-)
diff --git a/ci/scripts/matlab_build.sh b/ci/scripts/matlab_build.sh
index 656805275e..4acd4d3b82 100755
--- a/ci/scripts/matlab_build.sh
+++ b/ci/scripts/matlab_build.sh
@@ -25,6 +25,13 @@ source_dir=${base_dir}/matlab
build_dir=${base_dir}/matlab/build
install_dir=${base_dir}/matlab/install
-cmake -S ${source_dir} -B ${build_dir} -G Ninja -D MATLAB_BUILD_TESTS=ON -D
CMAKE_INSTALL_PREFIX=${install_dir} -D MATLAB_ADD_INSTALL_DIR_TO_SEARCH_PATH=OFF
+cmake \
+ -S ${source_dir} \
+ -B ${build_dir} \
+ -G Ninja \
+ -D MATLAB_ARROW_INTERFACE=ON \
+ -D MATLAB_BUILD_TESTS=ON \
+ -D CMAKE_INSTALL_PREFIX=${install_dir} \
+ -D MATLAB_ADD_INSTALL_DIR_TO_SEARCH_PATH=OFF
cmake --build ${build_dir} --config Release --target install
ctest --test-dir ${build_dir}
diff --git a/matlab/CMakeLists.txt b/matlab/CMakeLists.txt
index fbfd13edf3..ed3efbd6ea 100644
--- a/matlab/CMakeLists.txt
+++ b/matlab/CMakeLists.txt
@@ -32,39 +32,66 @@ function(build_arrow)
message(SEND_ERROR "Error: unrecognized arguments:
${ARG_UNPARSED_ARGUMENTS}")
endif()
- # If Arrow needs to be built, the default location will be within the build
tree.
set(ARROW_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/arrow_ep-prefix")
-
- if(WIN32)
- # The shared library is located in the "bin" directory.
- set(ARROW_SHARED_LIBRARY_DIR "${ARROW_PREFIX}/bin")
-
- # Imported libraries are used
- set(ARROW_IMPORT_LIB_FILENAME
- "${CMAKE_IMPORT_LIBRARY_PREFIX}arrow${CMAKE_IMPORT_LIBRARY_SUFFIX}")
- set(ARROW_IMPORT_LIB "${ARROW_PREFIX}/lib/${ARROW_IMPORT_LIB_FILENAME}")
- else()
- # The shared library is located in the "lib" directory.
- set(ARROW_SHARED_LIBRARY_DIR "${ARROW_PREFIX}/lib")
- endif()
-
- set(ARROW_SHARED_LIB_FILENAME
- "${CMAKE_SHARED_LIBRARY_PREFIX}arrow${CMAKE_SHARED_LIBRARY_SUFFIX}")
- set(ARROW_SHARED_LIB
"${ARROW_SHARED_LIBRARY_DIR}/${ARROW_SHARED_LIB_FILENAME}")
-
set(ARROW_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/arrow_ep-build")
set(ARROW_CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${ARROW_PREFIX}"
"-DCMAKE_INSTALL_LIBDIR=lib" "-DARROW_BUILD_STATIC=OFF")
- set(ARROW_INCLUDE_DIR "${ARROW_PREFIX}/include")
- # The output libraries need to be guaranteed to be available for linking the
test
- # executables.
- if(WIN32)
- # On Windows, add the Arrow link library as a BUILD_BYPRODUCTS for
arrow_ep.
- set(ARROW_BUILD_BYPRODUCTS "${ARROW_IMPORT_LIB}")
+ if(Arrow_FOUND
+ AND NOT GTest_FOUND
+ AND ARG_BUILD_GTEST)
+ # If find_package has already found a valid Arrow installation, then
+ # we don't want to link against the Arrow libraries that will be built
+ # from source.
+ #
+ # However, we still need to create a library target to trigger building
+ # of the arrow_ep target, which will ultimately build the bundled
+ # GoogleTest binaries.
+ add_library(arrow_shared_for_gtest SHARED IMPORTED)
+ set(ARROW_LIBRARY_TARGET arrow_shared_for_gtest)
else()
- # On Linux and macOS, add the Arrow shared library as a BUILD_BYPRODUCTS
for arrow_ep.
- set(ARROW_BUILD_BYPRODUCTS "${ARROW_SHARED_LIB}")
+ add_library(arrow_shared SHARED IMPORTED)
+ set(ARROW_LIBRARY_TARGET arrow_shared)
+
+ # Set the runtime shared library (.dll, .so, or .dylib)
+ if(WIN32)
+ # The shared library (i.e. .dll) is located in the "bin" directory.
+ set(ARROW_SHARED_LIBRARY_DIR "${ARROW_PREFIX}/bin")
+ else()
+ # The shared library (i.e. .so or .dylib) is located in the "lib"
directory.
+ set(ARROW_SHARED_LIBRARY_DIR "${ARROW_PREFIX}/lib")
+ endif()
+
+ set(ARROW_SHARED_LIB_FILENAME
+ "${CMAKE_SHARED_LIBRARY_PREFIX}arrow${CMAKE_SHARED_LIBRARY_SUFFIX}")
+ set(ARROW_SHARED_LIB
"${ARROW_SHARED_LIBRARY_DIR}/${ARROW_SHARED_LIB_FILENAME}")
+
+ set_target_properties(arrow_shared PROPERTIES IMPORTED_LOCATION
${ARROW_SHARED_LIB})
+
+ # Set the link-time import library (.lib)
+ if(WIN32)
+ # The import library (i.e. .lib) is located in the "lib" directory.
+ set(ARROW_IMPORT_LIB_FILENAME
+ "${CMAKE_IMPORT_LIBRARY_PREFIX}arrow${CMAKE_IMPORT_LIBRARY_SUFFIX}")
+ set(ARROW_IMPORT_LIB "${ARROW_PREFIX}/lib/${ARROW_IMPORT_LIB_FILENAME}")
+
+ set_target_properties(arrow_shared PROPERTIES IMPORTED_IMPLIB
${ARROW_IMPORT_LIB})
+ endif()
+
+ # Set the include directories
+ set(ARROW_INCLUDE_DIR "${ARROW_PREFIX}/include")
+ file(MAKE_DIRECTORY "${ARROW_INCLUDE_DIR}")
+ set_target_properties(arrow_shared PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
+ ${ARROW_INCLUDE_DIR})
+
+ # Set the build byproducts for the ExternalProject build
+ # The appropriate libraries need to be guaranteed to be available when
linking the test
+ # executables.
+ if(WIN32)
+ set(ARROW_BUILD_BYPRODUCTS "${ARROW_IMPORT_LIB}")
+ else()
+ set(ARROW_BUILD_BYPRODUCTS "${ARROW_SHARED_LIB}")
+ endif()
endif()
# Building the Arrow C++ libraries and bundled GoogleTest binaries requires
ExternalProject.
@@ -80,29 +107,6 @@ function(build_arrow)
CMAKE_ARGS "${ARROW_CMAKE_ARGS}"
BUILD_BYPRODUCTS "${ARROW_BUILD_BYPRODUCTS}")
- set(ARROW_LIBRARY_TARGET arrow_shared)
-
- # If find_package has already found a valid Arrow installation, then
- # we don't want to link against the newly built arrow_shared library.
- # However, we still need to create a library target to trigger building
- # of the arrow_ep target, which will ultimately build the bundled
- # GoogleTest binaries.
- if(Arrow_FOUND)
- set(ARROW_LIBRARY_TARGET arrow_shared_for_gtest)
- endif()
-
- file(MAKE_DIRECTORY "${ARROW_INCLUDE_DIR}")
- add_library(${ARROW_LIBRARY_TARGET} SHARED IMPORTED)
- set_target_properties(${ARROW_LIBRARY_TARGET}
- PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
${ARROW_INCLUDE_DIR}
- IMPORTED_LOCATION ${ARROW_SHARED_LIB})
- if(WIN32)
- # On Windows, IMPORTED_IMPLIB is set to the location of arrow.lib, which is
- # for linking arrow_matlab against the Arrow C++ library.
- set_target_properties(${ARROW_LIBRARY_TARGET} PROPERTIES IMPORTED_IMPLIB
-
${ARROW_IMPORT_LIB})
- endif()
-
add_dependencies(${ARROW_LIBRARY_TARGET} arrow_ep)
if(ARG_BUILD_GTEST)
@@ -202,13 +206,16 @@ endif()
option(MATLAB_BUILD_TESTS "Build the C++ tests for the MATLAB interface" OFF)
-# Grab CMAKE Modules from the CPP interface.
-set(CPP_CMAKE_MODULES "${CMAKE_SOURCE_DIR}/../cpp/cmake_modules")
-if(EXISTS "${CPP_CMAKE_MODULES}")
- set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CPP_CMAKE_MODULES})
-endif()
+# Add tools/cmake directory to the CMAKE_MODULE_PATH.
+list(PREPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/tools/cmake)
-set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake_modules)
+# Configure find_package to look for arrow-config.cmake in Config mode
+# underneath the Arrow installation directory hierarchy specified
+# by ARROW_HOME or Arrow_ROOT.
+# NOTE: ARROW_HOME is supported for backwards compatibility.
+if(ARROW_HOME AND NOT Arrow_ROOT)
+ set(Arrow_ROOT "${ARROW_HOME}")
+endif()
# Multi-Configuration generators (e.g. Visual Studio or XCode) place their
build artifacts
# in a subdirectory named ${CMAKE_BUILD_TYPE} by default, where
${CMAKE_BUILD_TYPE} varies
@@ -228,7 +235,7 @@ if(MATLAB_BUILD_TESTS)
if(NOT GTest_FOUND)
# find_package(Arrow) supports custom ARROW_HOME as well as package
# managers.
- find_package(Arrow)
+ find_package(Arrow QUIET)
# Trigger an automatic build of the Arrow C++ libraries and bundled
# GoogleTest binaries. If a valid Arrow installation was not already
# found by find_package, then build_arrow will use the Arrow
@@ -258,7 +265,7 @@ if(MATLAB_BUILD_TESTS)
"${GTEST_MAIN_SHARED_LIBRARY_LIB}")
endif()
- find_package(Arrow)
+ find_package(Arrow QUIET)
if(NOT Arrow_FOUND)
# Trigger an automatic build of the Arrow C++ libraries.
build_arrow()
@@ -266,7 +273,7 @@ if(MATLAB_BUILD_TESTS)
endif()
else()
- find_package(Arrow)
+ find_package(Arrow QUIET)
if(NOT Arrow_FOUND)
build_arrow()
endif()
@@ -317,6 +324,51 @@ matlab_add_mex(R2018a
target_include_directories(mexcall PRIVATE ${CPP_SOURCE_DIR})
+# ARROW_SHARED_LIB
+# On Windows, this will be ARROW_HOME/bin/arrow.dll and on Linux and macOS, it
is the arrow.so/dylib in the newly built arrow_shared library.
+if(NOT Arrow_FOUND)
+ message(STATUS "ARROW_SHARED_LIB will be set using IMPORTED_LOCATION value
when building."
+ )
+ get_target_property(ARROW_SHARED_LIB arrow_shared IMPORTED_LOCATION)
+else()
+ # If not building Arrow, ARROW_SHARED_LIB derived from ARROW_PREFIX set to
the ARROW_HOME specified with cmake would be non-empty.
+ message(STATUS "ARROW_SHARED_LIB: ${ARROW_SHARED_LIB}")
+endif()
+
+# ARROW_LINK_LIB
+# On Windows, we use the arrow.lib for linking arrow_matlab against the Arrow
C++ library.
+# The location of arrow.lib is previously saved in IMPORTED_IMPLIB.
+if(WIN32)
+ # If not building Arrow, IMPORTED_IMPLIB will be empty.
+ # Then set ARROW_LINK_LIB to ARROW_IMPORT_LIB which would have been derived
from ARROW_PREFIX set to the ARROW_HOME specified with cmake. This will avoid
the ARROW_LINK_LIB set to NOTFOUND error.
+ # The ARROW_IMPORT_LIB should be ARROW_HOME/lib/arrow.lib on Windows.
+ if(NOT Arrow_FOUND)
+ message(STATUS "ARROW_LINK_LIB will be set using IMPORTED_IMPLIB value
when building."
+ )
+ get_target_property(ARROW_LINK_LIB arrow_shared IMPORTED_IMPLIB)
+ else()
+ set(ARROW_LINK_LIB "${ARROW_IMPORT_LIB}")
+ message(STATUS "Setting ARROW_LINK_LIB to ARROW_IMPORT_LIB:
${ARROW_IMPORT_LIB}, which is derived from the ARROW_HOME provided."
+ )
+ endif()
+else()
+ # On Linux and macOS, it is the arrow.so/dylib in the newly built
arrow_shared library used for linking.
+ # On Unix, this is the same as ARROW_SHARED_LIB.
+ message(STATUS "Setting ARROW_LINK_LIB to ARROW_SHARED_LIB as they are same
on Unix.")
+ set(ARROW_LINK_LIB "${ARROW_SHARED_LIB}")
+endif()
+
+# ARROW_INCLUDE_DIR should be set so that header files in the include
directory can be found correctly.
+# The value of ARROW_INCLUDE_DIR should be ARROW_HOME/include on all platforms.
+if(NOT Arrow_FOUND)
+ message(STATUS "ARROW_INCLUDE_DIR will be set using
INTERFACE_INCLUDE_DIRECTORIES value when building."
+ )
+ get_target_property(ARROW_INCLUDE_DIR arrow_shared
INTERFACE_INCLUDE_DIRECTORIES)
+else()
+ # If not building Arrow, ARROW_INCLUDE_DIR derived from ARROW_PREFIX set to
the ARROW_HOME specified with cmake would be non-empty.
+ message(STATUS "ARROW_INCLUDE_DIR: ${ARROW_INCLUDE_DIR}")
+endif()
+
#
##############################################################################
# C++ Tests
#
##############################################################################
@@ -396,9 +448,13 @@ endif()
# Create a subdirectory at CMAKE_INSTALL_PREFIX to install the interface.
set(CMAKE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/arrow_matlab")
+if(MATLAB_ARROW_INTERFACE)
+ include(BuildMatlabArrowInterface)
+endif()
+
# Create a package hierarchy at CMAKE_INSTALL_PREFIX to install the mex
function
# and dependencies.
-set(CMAKE_PACKAGED_INSTALL_DIR
"${CMAKE_INSTALL_PREFIX}/arrow_matlab/+arrow/+cpp")
+set(CMAKE_PACKAGED_INSTALL_DIR "${CMAKE_INSTALL_DIR}/+arrow/+cpp")
# Install MATLAB source files.
# On macOS, exclude '.DS_Store' files in the source tree from installation.
@@ -413,16 +469,9 @@ install(TARGETS arrow_matlab mexcall
RUNTIME DESTINATION ${CMAKE_PACKAGED_INSTALL_DIR}
LIBRARY DESTINATION ${CMAKE_PACKAGED_INSTALL_DIR})
-get_target_property(ARROW_SHARED_LIB arrow_shared IMPORTED_LOCATION)
get_filename_component(ARROW_SHARED_LIB_DIR ${ARROW_SHARED_LIB} DIRECTORY)
get_filename_component(ARROW_SHARED_LIB_FILENAME ${ARROW_SHARED_LIB} NAME_WE)
-if(WIN32)
- # On Windows, arrow.dll must be installed to to CMAKE_PACKAGED_INSTALL_DIR
regardless of whether
- # Arrow_FOUND is true or false.
- install(FILES ${ARROW_SHARED_LIB} DESTINATION
"${CMAKE_PACKAGED_INSTALL_DIR}")
-endif()
-
# On macOS, use the RPATH values below for runtime dependency resolution. This
enables
# relocation of the installation directory.
if(APPLE)
diff --git a/matlab/src/cpp/arrow/matlab/array/proxy/float64_array.cc
b/matlab/src/cpp/arrow/matlab/array/proxy/float64_array.cc
new file mode 100644
index 0000000000..4f25912b9e
--- /dev/null
+++ b/matlab/src/cpp/arrow/matlab/array/proxy/float64_array.cc
@@ -0,0 +1,25 @@
+// 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.
+
+#include "float64_array.h"
+
+namespace arrow::matlab::array::proxy {
+void Float64Array::Print(libmexclass::proxy::method::Context& context) {
+ // TODO: Return an MDA string representation of the Arrow array.
+ std::cout << array->ToString() << std::endl;
+}
+} // namespace arrow::matlab::array::proxy
diff --git a/matlab/src/cpp/arrow/matlab/array/proxy/float64_array.h
b/matlab/src/cpp/arrow/matlab/array/proxy/float64_array.h
new file mode 100644
index 0000000000..3d6e449326
--- /dev/null
+++ b/matlab/src/cpp/arrow/matlab/array/proxy/float64_array.h
@@ -0,0 +1,60 @@
+// 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.
+
+#pragma once
+
+#include "arrow/array.h"
+#include "arrow/builder.h"
+
+#include "libmexclass/proxy/Proxy.h"
+
+namespace arrow::matlab::array::proxy {
+class Float64Array : public libmexclass::proxy::Proxy {
+ public:
+ Float64Array(const libmexclass::proxy::FunctionArguments&
constructor_arguments) {
+ // Get the mxArray from constructor arguments
+ const ::matlab::data::TypedArray<double> double_mda =
constructor_arguments[0];
+
+ // Get raw pointer of mxArray
+ auto it(double_mda.cbegin());
+ auto dt = it.operator->();
+
+ // Pass pointer to Arrow array constructor that takes a buffer
+ // Do not make a copy when creating arrow::Buffer
+ std::shared_ptr<arrow::Buffer> buffer(
+ new arrow::Buffer(reinterpret_cast<const uint8_t*>(dt),
+ sizeof(double) *
double_mda.getNumberOfElements()));
+
+ // Construct arrow::NumericArray specialization using
arrow::Buffer.
+ // pass in nulls information...we could compute and provide the
number of nulls here too
+ std::shared_ptr<arrow::Array> array_wrapper(
+ new
arrow::NumericArray<arrow::DoubleType>(double_mda.getNumberOfElements(), buffer,
+ nullptr, // TODO: fill
validity bitmap with data
+ -1));
+
+ array = array_wrapper;
+
+ // Register Proxy methods.
+ REGISTER_METHOD(Float64Array, Print);
+ }
+ private:
+ void Print(libmexclass::proxy::method::Context& context);
+
+ // "Raw" arrow::Array
+ std::shared_ptr<arrow::Array> array;
+};
+} // namespace arrow::matlab::array::proxy
diff --git a/matlab/src/cpp/arrow/matlab/mex/gateway.cc
b/matlab/src/cpp/arrow/matlab/mex/gateway.cc
new file mode 100644
index 0000000000..78ce6e274e
--- /dev/null
+++ b/matlab/src/cpp/arrow/matlab/mex/gateway.cc
@@ -0,0 +1,30 @@
+// 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.
+
+#include "mex.hpp"
+#include "mexAdapter.hpp"
+
+#include "libmexclass/mex/gateway.h"
+
+#include "arrow/matlab/proxy/factory.h"
+
+class MexFunction : public matlab::mex::Function {
+ public:
+ void operator()(matlab::mex::ArgumentList outputs,
matlab::mex::ArgumentList inputs) {
+ libmexclass::mex::gateway<arrow::matlab::proxy::Factory>(inputs,
outputs, getEngine());
+ }
+};
diff --git a/matlab/src/cpp/arrow/matlab/proxy/factory.cc
b/matlab/src/cpp/arrow/matlab/proxy/factory.cc
new file mode 100644
index 0000000000..9bf7ec2dc9
--- /dev/null
+++ b/matlab/src/cpp/arrow/matlab/proxy/factory.cc
@@ -0,0 +1,36 @@
+// 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.
+
+#include "arrow/matlab/array/proxy/float64_array.h"
+
+#include "factory.h"
+
+#include <iostream>
+
+namespace arrow::matlab::proxy {
+
+std::shared_ptr<Proxy> Factory::make_proxy(const ClassName& class_name, const
FunctionArguments& constructor_arguments) {
+
+ // Register MATLAB Proxy classes with corresponding C++ Proxy classes.
+ REGISTER_PROXY(arrow.array.proxy.Float64Array,
arrow::matlab::array::proxy::Float64Array);
+
+ // TODO: Decide what to do in the case that there isn't a Proxy match.
+ std::cout << "Did not find a matching C++ proxy for: " + class_name <<
std::endl;
+ return nullptr;
+};
+
+}
diff --git a/matlab/src/cpp/arrow/matlab/proxy/factory.h
b/matlab/src/cpp/arrow/matlab/proxy/factory.h
new file mode 100644
index 0000000000..6f68ff4ac9
--- /dev/null
+++ b/matlab/src/cpp/arrow/matlab/proxy/factory.h
@@ -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.
+
+#pragma once
+
+#include "libmexclass/proxy/Factory.h"
+
+namespace arrow::matlab::proxy {
+
+using namespace libmexclass::proxy;
+
+class Factory : public libmexclass::proxy::Factory {
+ public:
+ Factory() { }
+ virtual std::shared_ptr<Proxy> make_proxy(const ClassName& class_name,
const FunctionArguments& constructor_arguments);
+};
+
+}
diff --git a/matlab/src/matlab/+arrow/+array/Float64Array.m
b/matlab/src/matlab/+arrow/+array/Float64Array.m
new file mode 100644
index 0000000000..71d56e6cc0
--- /dev/null
+++ b/matlab/src/matlab/+arrow/+array/Float64Array.m
@@ -0,0 +1,44 @@
+classdef Float64Array < matlab.mixin.CustomDisplay
+ % arrow.array.Float64Array
+
+ % 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.
+
+ properties (Access=private)
+ Proxy
+ end
+
+ properties (Access=private)
+ MatlabArray
+ end
+
+ methods
+ function obj = Float64Array(matlabArray)
+ obj.MatlabArray = matlabArray;
+ obj.Proxy = libmexclass.proxy.Proxy("Name",
"arrow.array.proxy.Float64Array", "ConstructorArguments", {obj.MatlabArray});
+ end
+
+ function Print(obj)
+ obj.Proxy.Print();
+ end
+ end
+
+ methods (Access=protected)
+ function displayScalarObject(obj)
+ obj.Print();
+ end
+ end
+
+end
diff --git a/matlab/test/arrow/array/tFloat64Array.m
b/matlab/test/arrow/array/tFloat64Array.m
new file mode 100755
index 0000000000..f104ad4a7d
--- /dev/null
+++ b/matlab/test/arrow/array/tFloat64Array.m
@@ -0,0 +1,41 @@
+classdef tFloat64Array < matlab.unittest.TestCase
+ % Tests for arrow.array.Float64Array
+
+ % 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.
+
+ methods(TestClassSetup)
+ function verifyOnMatlabPath(testCase)
+ % arrow.array.Float64Array must be on the MATLAB path.
+ testCase.assertTrue(~isempty(which('arrow.array.Float64Array')),
...
+ '''arrow.array.Float64Array'' must be on the MATLAB path. Use
''addpath'' to add folders to the MATLAB path.');
+ end
+ end
+
+ methods(TestMethodSetup)
+ function setupTempWorkingDirectory(testCase)
+ import matlab.unittest.fixtures.WorkingFolderFixture;
+ testCase.applyFixture(WorkingFolderFixture);
+ end
+ end
+
+ methods(Test)
+ function Basic(testCase)
+ A = arrow.array.Float64Array([1, 2, 3]);
+ className = string(class(A));
+ testCase.verifyEqual(className, "arrow.array.Float64Array");
+ end
+ end
+end
diff --git a/matlab/tools/cmake/BuildMatlabArrowInterface.cmake
b/matlab/tools/cmake/BuildMatlabArrowInterface.cmake
new file mode 100644
index 0000000000..59c48c0235
--- /dev/null
+++ b/matlab/tools/cmake/BuildMatlabArrowInterface.cmake
@@ -0,0 +1,108 @@
+# 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.
+
+# ----------------------------------
+# Configure libmexclass FetchContent
+# ----------------------------------
+
+set(MATLAB_ARROW_LIBMEXCLASS_CLIENT_FETCH_CONTENT_NAME libmexclass)
+# TODO: Consider using SSH URL for the Git Repository when
+# libmexclass is accessible for CI without permission issues.
+set(MATLAB_ARROW_LIBMEXCLASS_CLIENT_FETCH_CONTENT_GIT_REPOSITORY
"https://github.com/mathworks/libmexclass.git")
+# Use a specific Git commit hash to avoid libmexclass version changing
unexpectedly.
+set(MATLAB_ARROW_LIBMEXCLASS_CLIENT_FETCH_CONTENT_GIT_TAG "44c15d0")
+set(MATLAB_ARROW_LIBMEXCLASS_CLIENT_FETCH_CONTENT_SOURCE_SUBDIR
"libmexclass/cpp")
+
+# ------------------------------------------
+# Configure libmexclass Client Proxy Library
+# ------------------------------------------
+
+set(MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_LIBRARY_NAME arrowproxy)
+set(MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_LIBRARY_ROOT_INCLUDE_DIR
"${CMAKE_SOURCE_DIR}/src/cpp")
+set(MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_INCLUDE_DIR
"${CMAKE_SOURCE_DIR}/src/cpp/arrow/matlab/array/proxy")
+set(MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_SOURCES
"${CMAKE_SOURCE_DIR}/src/cpp/arrow/matlab/array/proxy/float64_array.cc")
+set(MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_FACTORY_INCLUDE_DIR
"${CMAKE_SOURCE_DIR}/src/cpp/arrow/matlab/proxy")
+set(MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_FACTORY_SOURCES
"${CMAKE_SOURCE_DIR}/src/cpp/arrow/matlab/proxy/factory.cc")
+set(MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_LIBRARY_INCLUDE_DIRS
${MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_LIBRARY_ROOT_INCLUDE_DIR}
+
${MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_INCLUDE_DIR}
+
${MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_FACTORY_INCLUDE_DIR})
+set(MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_LIBRARY_SOURCES
${MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_SOURCES}
+
${MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_FACTORY_SOURCES})
+# ----------------------------------------
+# Configure libmexclass Client MEX Gateway
+# ----------------------------------------
+
+set(MATLAB_ARROW_LIBMEXCLASS_CLIENT_MEX_GATEWAY_NAME gateway)
+set(MATLAB_ARROW_LIBMEXCLASS_CLIENT_MEX_GATEWAY_SOURCES
"${CMAKE_SOURCE_DIR}/src/cpp/arrow/matlab/mex/gateway.cc")
+
+# ---------------------------------------
+# Download libmexclass Using FetchContent
+# ---------------------------------------
+
+# Include libmexclass using FetchContent.
+include(FetchContent)
+FetchContent_Declare(
+ ${MATLAB_ARROW_LIBMEXCLASS_CLIENT_FETCH_CONTENT_NAME}
+ GIT_REPOSITORY
${MATLAB_ARROW_LIBMEXCLASS_CLIENT_FETCH_CONTENT_GIT_REPOSITORY}
+ GIT_TAG ${MATLAB_ARROW_LIBMEXCLASS_CLIENT_FETCH_CONTENT_GIT_TAG}
+ SOURCE_SUBDIR
${MATLAB_ARROW_LIBMEXCLASS_CLIENT_FETCH_CONTENT_SOURCE_SUBDIR}
+)
+FetchContent_MakeAvailable(
+ ${MATLAB_ARROW_LIBMEXCLASS_CLIENT_FETCH_CONTENT_NAME}
+)
+
+# ------------------------------------
+# Add libmexclass Client Proxy Library
+# ------------------------------------
+
+if(NOT TARGET arrow_shared)
+ message(FATAL_ERROR "The Arrow C++ libraries must be available to build
the MATLAB Interface to Arrow.")
+endif()
+
+libmexclass_client_add_proxy_library(
+ NAME ${MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_LIBRARY_NAME}
+ SOURCES ${MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_LIBRARY_SOURCES}
+ INCLUDE_DIRS ${MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_LIBRARY_INCLUDE_DIRS}
+ LINK_LIBRARIES arrow_shared
+)
+# Use C++17
+target_compile_features(${MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_LIBRARY_NAME}
PRIVATE cxx_std_17)
+
+# When building Arrow from source, Arrow must be built before building the
client Proxy library.
+if(TARGET arrow_ep)
+ add_dependencies(${MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_LIBRARY_NAME}
arrow_ep)
+endif()
+
+# ----------------------------------
+# Add libmexclass Client MEX Gateway
+# ----------------------------------
+
+libmexclass_client_add_mex_gateway(
+ NAME ${MATLAB_ARROW_LIBMEXCLASS_CLIENT_MEX_GATEWAY_NAME}
+ CLIENT_PROXY_LIBRARY_NAME
${MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_LIBRARY_NAME}
+ SOURCES ${MATLAB_ARROW_LIBMEXCLASS_CLIENT_MEX_GATEWAY_SOURCES}
+)
+
+# --------------------------
+# Install libmexclass Client
+# --------------------------
+
+libmexclass_client_install(
+ CLIENT_PROXY_LIBRARY_NAME
${MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_LIBRARY_NAME}
+ CLIENT_MEX_GATEWAY_NAME ${MATLAB_ARROW_LIBMEXCLASS_CLIENT_MEX_GATEWAY_NAME}
+ DESTINATION ${CMAKE_INSTALL_DIR}
+)