Skip to content

Commit 274f09f

Browse files
committed
Use Refs and make module precompile safe
1 parent 2202c9b commit 274f09f

File tree

5 files changed

+260
-214
lines changed

5 files changed

+260
-214
lines changed

src/MATLAB.jl

Lines changed: 96 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
module MATLAB
1+
__precompile__()
22

3-
using Base.Libdl: dlopen, dlsym, RTLD_LAZY, RTLD_GLOBAL
3+
module MATLAB
44

55
import Base: eltype, close, size, copy, ndims, unsafe_convert
66

@@ -41,23 +41,113 @@ end
4141
include("mxbase.jl")
4242
include("mxarray.jl")
4343
include("matfile.jl")
44-
4544
include("mstatements.jl")
4645
include("engine.jl")
4746
include("matstr.jl")
4847

4948
function __init__()
49+
50+
# load libraries
51+
52+
libmx[] = Libdl.dlopen(joinpath(matlab_lib_path, "libmx"), Libdl.RTLD_GLOBAL)
53+
libmat[] = Libdl.dlopen(joinpath(matlab_lib_path, "libmat"), Libdl.RTLD_GLOBAL)
54+
libeng[] = Libdl.dlopen(joinpath(matlab_lib_path, "libeng"), Libdl.RTLD_GLOBAL)
55+
56+
57+
# load functions to access mxArray
58+
59+
_mx_free[] = mxfunc(:mxFree)
60+
61+
_mx_get_classid[] = mxfunc(:mxGetClassID)
62+
_mx_get_m[] = mxfunc(:mxGetM)
63+
_mx_get_n[] = mxfunc(:mxGetN)
64+
_mx_get_nelems[] = mxfunc(:mxGetNumberOfElements)
65+
_mx_get_ndims[] = mxfunc(:mxGetNumberOfDimensions_730)
66+
_mx_get_elemsize[] = mxfunc(:mxGetElementSize)
67+
_mx_get_data[] = mxfunc(:mxGetData)
68+
_mx_get_dims[] = mxfunc(:mxGetDimensions_730)
69+
_mx_get_nfields[] = mxfunc(:mxGetNumberOfFields)
70+
_mx_get_pr[] = mxfunc(:mxGetPr)
71+
_mx_get_pi[] = mxfunc(:mxGetPi)
72+
_mx_get_ir[] = mxfunc(:mxGetIr_730)
73+
_mx_get_jc[] = mxfunc(:mxGetJc_730)
74+
75+
_mx_is_double[] = mxfunc(:mxIsDouble)
76+
_mx_is_single[] = mxfunc(:mxIsSingle)
77+
_mx_is_int64[] = mxfunc(:mxIsInt64)
78+
_mx_is_uint64[] = mxfunc(:mxIsUint64)
79+
_mx_is_int32[] = mxfunc(:mxIsInt32)
80+
_mx_is_uint32[] = mxfunc(:mxIsUint32)
81+
_mx_is_int16[] = mxfunc(:mxIsInt16)
82+
_mx_is_uint16[] = mxfunc(:mxIsUint16)
83+
_mx_is_int8[] = mxfunc(:mxIsInt8)
84+
_mx_is_uint8[] = mxfunc(:mxIsUint8)
85+
_mx_is_char[] = mxfunc(:mxIsChar)
86+
87+
_mx_is_numeric[] = mxfunc(:mxIsNumeric)
88+
_mx_is_logical[] = mxfunc(:mxIsLogical)
89+
_mx_is_complex[] = mxfunc(:mxIsComplex)
90+
_mx_is_sparse[] = mxfunc(:mxIsSparse)
91+
_mx_is_empty[] = mxfunc(:mxIsEmpty)
92+
_mx_is_struct[] = mxfunc(:mxIsStruct)
93+
_mx_is_cell[] = mxfunc(:mxIsCell)
94+
95+
96+
# load functions to create & delete MATLAB array
97+
98+
_mx_create_numeric_mat[] = mxfunc(:mxCreateNumericMatrix_730)
99+
_mx_create_numeric_arr[] = mxfunc(:mxCreateNumericArray_730)
100+
101+
_mx_create_double_scalar[] = mxfunc(:mxCreateDoubleScalar)
102+
_mx_create_logical_scalar[] = mxfunc(:mxCreateLogicalScalar)
103+
104+
_mx_create_sparse[] = mxfunc(:mxCreateSparse_730)
105+
_mx_create_sparse_logical[] = mxfunc(:mxCreateSparseLogicalMatrix_730)
106+
107+
_mx_create_string[] = mxfunc(:mxCreateString)
108+
_mx_create_char_array[] = mxfunc(:mxCreateCharArray_730)
109+
110+
_mx_create_cell_array[] = mxfunc(:mxCreateCellArray_730)
111+
112+
_mx_create_struct_matrix[] = mxfunc(:mxCreateStructMatrix_730)
113+
_mx_create_struct_array[] = mxfunc(:mxCreateStructArray_730)
114+
115+
_mx_get_cell[] = mxfunc(:mxGetCell_730)
116+
_mx_set_cell[] = mxfunc(:mxSetCell_730)
117+
118+
_mx_get_field[] = mxfunc(:mxGetField_730)
119+
_mx_set_field[] = mxfunc(:mxSetField_730)
120+
_mx_get_field_bynum[] = mxfunc(:mxGetFieldByNumber_730)
121+
_mx_get_fieldname[] = mxfunc(:mxGetFieldNameByNumber)
122+
123+
_mx_get_string[] = mxfunc(:mxGetString_730)
124+
125+
126+
# load I/O mat functions
127+
128+
_mat_open[] = matfunc(:matOpen)
129+
_mat_close[] = matfunc(:matClose)
130+
_mat_get_variable[] = matfunc(:matGetVariable)
131+
_mat_put_variable[] = matfunc(:matPutVariable)
132+
_mat_get_dir[] = matfunc(:matGetDir)
133+
134+
50135
if is_windows()
51-
global persistent_msession
52136
# workaround "primary message table for module 77" error
53137
# creates a dummy Engine session and keeps it open so the libraries used by all other
54138
# Engine clients are not loaded and unloaded repeatedly
55139
# see: https://www.mathworks.com/matlabcentral/answers/305877-what-is-the-primary-message-table-for-module-77
56-
persistent_msession = MSession(0)
140+
global persistent_msession = MSession(0)
57141
end
58142
end
59143

60-
# deprecations
144+
145+
###########################################################
146+
#
147+
# deprecations
148+
#
149+
###########################################################
150+
61151
function nfields(mx::MxArray)
62152
Base.depwarn("MATLAB.nfields is deprecated, use mxnfields instead.", :nfields)
63153
return mxfields(mx)
@@ -76,5 +166,4 @@ end
76166

77167
@deprecate mxempty() mxarray(Float64,0,0)
78168

79-
80169
end

src/engine.jl

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@ type MSession
1515
bufptr::Ptr{UInt8}
1616

1717
function MSession(bufsize::Integer = default_output_buffer_size)
18-
global libeng
19-
libeng == C_NULL && load_libeng()
20-
@assert libeng != C_NULL
21-
2218
ep = ccall(engfunc(:engOpen), Ptr{Void}, (Ptr{UInt8},), default_startcmd)
2319
ep == C_NULL && throw(MEngineError("failed to open a MATLAB engine session"))
2420
# hide the MATLAB command window on Windows
@@ -56,8 +52,7 @@ function release(session::MSession)
5652
end
5753

5854
function close(session::MSession)
59-
# Close a MATLAB Engine session
60-
@assert libeng::Ptr{Void} != C_NULL
55+
# close a MATLAB Engine session
6156
ret = ccall(engfunc(:engClose), Cint, (Ptr{Void},), session)
6257
ret != 0 && throw(MEngineError("failed to close a MATLAB engine session (err = $ret)"))
6358
session.ptr = C_NULL
@@ -115,27 +110,25 @@ end
115110
###########################################################
116111

117112
function eval_string(session::MSession, stmt::String)
118-
# Evaluate a MATLAB statement in a given MATLAB session
119-
@assert libeng::Ptr{Void} != C_NULL
120-
113+
# evaluate a MATLAB statement in a given MATLAB session
121114
ret = ccall(engfunc(:engEvalString), Cint, (Ptr{Void}, Ptr{UInt8}), session, stmt)
122115
ret != 0 && throw(MEngineError("invalid engine session (err = $ret)"))
123116

124-
bufptr::Ptr{UInt8} = session.bufptr
117+
bufptr = session.bufptr
125118
if bufptr != C_NULL
126119
bs = unsafe_string(bufptr)
127120
if ~isempty(bs)
128121
print(bs)
129122
end
130123
end
124+
return nothing
131125
end
132126

133127
eval_string(stmt::String) = eval_string(get_default_msession(), stmt)
134128

135129

136130
function put_variable(session::MSession, name::Symbol, v::MxArray)
137-
# Put a variable into a MATLAB engine session
138-
@assert libeng::Ptr{Void} != C_NULL
131+
# put a variable into a MATLAB engine session
139132
ret = ccall(engfunc(:engPutVariable), Cint, (Ptr{Void}, Ptr{UInt8}, Ptr{Void}), session, string(name), v)
140133
ret != 0 && throw(MEngineError("failed to put the variable $(name) into a MATLAB session (err = $ret)"))
141134
return nothing
@@ -147,7 +140,6 @@ put_variable(name::Symbol, v) = put_variable(get_default_msession(), name, v)
147140

148141

149142
function get_mvariable(session::MSession, name::Symbol)
150-
@assert libeng::Ptr{Void} != C_NULL
151143
pv = ccall(engfunc(:engGetVariable), Ptr{Void}, (Ptr{Void}, Ptr{UInt8}), session, string(name))
152144
pv == C_NULL && throw(MEngineError("failed to get the variable $(name) from a MATLAB session"))
153145
return MxArray(pv)
@@ -307,5 +299,3 @@ function mxcall(session::MSession, mfun::Symbol, nout::Integer, in_args...)
307299
end
308300

309301
mxcall(mfun::Symbol, nout::Integer, in_args...) = mxcall(get_default_msession(), mfun, nout, in_args...)
310-
311-

src/matfile.jl

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# I/O with mat files
22

3-
const _mat_open = matfunc(:matOpen)
4-
const _mat_close = matfunc(:matClose)
5-
const _mat_get_variable = matfunc(:matGetVariable)
6-
const _mat_put_variable = matfunc(:matPutVariable)
7-
const _mat_get_dir = matfunc(:matGetDir)
3+
const _mat_open = Ref{Ptr{Void}}(0)
4+
const _mat_close = Ref{Ptr{Void}}(0)
5+
const _mat_get_variable = Ref{Ptr{Void}}(0)
6+
const _mat_put_variable = Ref{Ptr{Void}}(0)
7+
const _mat_get_dir = Ref{Ptr{Void}}(0)
88

99
# mat file open & close
1010

@@ -13,7 +13,7 @@ type MatFile
1313
filename::String
1414

1515
function MatFile(filename::String, mode::String)
16-
p = ccall(_mat_open, Ptr{Void}, (Ptr{Cchar}, Ptr{Cchar}),
16+
p = ccall(_mat_open[], Ptr{Void}, (Ptr{Cchar}, Ptr{Cchar}),
1717
filename, mode)
1818
new(p, filename)
1919
end
@@ -22,7 +22,7 @@ MatFile(filename::String) = MatFile(filename, "r")
2222

2323
function close(f::MatFile)
2424
if f.ptr != C_NULL
25-
ret = ccall(_mat_close, Cint, (Ptr{Void},), f.ptr)
25+
ret = ccall(_mat_close[], Cint, (Ptr{Void},), f.ptr)
2626
ret == 0 || error("Failed to close file.")
2727
end
2828
end
@@ -31,7 +31,7 @@ end
3131

3232
function get_mvariable(f::MatFile, name::String)
3333
f.ptr != C_NULL || error("Cannot get variable from a null file.")
34-
pm = ccall(_mat_get_variable, Ptr{Void}, (Ptr{Void}, Ptr{Cchar}),
34+
pm = ccall(_mat_get_variable[], Ptr{Void}, (Ptr{Void}, Ptr{Cchar}),
3535
f.ptr, name)
3636
pm != C_NULL || error("Attempt to get variable $(name) failed.")
3737
MxArray(pm)
@@ -45,7 +45,7 @@ get_variable(f::MatFile, name::Symbol) = jvalue(get_mvariable(f, name))
4545
function put_variable(f::MatFile, name::String, v::MxArray)
4646
f.ptr != C_NULL || error("Cannot put variable to a null file.")
4747
v.ptr != C_NULL || error("Cannot put an null variable.")
48-
ret = ccall(_mat_put_variable, Cint, (Ptr{Void}, Ptr{Cchar}, Ptr{Void}),
48+
ret = ccall(_mat_put_variable[], Cint, (Ptr{Void}, Ptr{Cchar}, Ptr{Void}),
4949
f.ptr, name, v.ptr)
5050
ret == 0 || error("Attempt to put variable $(name) failed.")
5151
end
@@ -75,14 +75,14 @@ end
7575
function variable_names(f::MatFile)
7676
# get a list of all variable names
7777
_n = Cint[0]
78-
_a = ccall(_mat_get_dir, Ptr{Ptr{Cchar}}, (Ptr{Void}, Ptr{Cint}),
78+
_a = ccall(_mat_get_dir[], Ptr{Ptr{Cchar}}, (Ptr{Void}, Ptr{Cint}),
7979
f.ptr, _n)
8080

8181
n = Int(_n[1])
8282
a = unsafe_wrap(Array, _a, (n,))
8383

8484
names = String[unsafe_string(s) for s in a]
85-
ccall(_mx_free, Void, (Ptr{Void},), _a)
85+
ccall(_mx_free[], Void, (Ptr{Void},), _a)
8686
return names
8787
end
8888

@@ -107,4 +107,3 @@ function read_matfile(filename::String)
107107
end
108108
return r
109109
end
110-

0 commit comments

Comments
 (0)