diff --git a/.gitignore b/.gitignore index 95731a5..be57604 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ /Manifest.toml /docs/Manifest.toml /docs/build/ +/language_wrappers/Manifest.toml +/language_wrappers/bindinginfo_libNMFMerge.log diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 9e26dfe..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/language_wrappers/Makefile b/language_wrappers/Makefile new file mode 100644 index 0000000..6dc2625 --- /dev/null +++ b/language_wrappers/Makefile @@ -0,0 +1,55 @@ +# This Makefile template requires the following variables to be set +# in the environment or on the command-line: +# JULIA: path to julia[.exe] executable +# BIN: binary build directory + +ifndef JULIA + $(error "Please pass JULIA=[path of target julia binary], or set as environment variable!") +endif +ifndef BIN + $(error "Please pass BIN=[path of build directory], or set as environment variable!") +endif + +#============================================================================= +# location of test source +SRCDIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) +PKGDIR := $(abspath $(dir $(SRCDIR))) +JULIAHOME := $(abspath $(JULIA)/../..) +# BUILDSCRIPT := $(BIN)/../share/julia/juliac-buildscript.jl +# include $(JULIAHOME)/Make.inc + +# FIXME +SHLIB_EXT := so + +# get the executable suffix, if any +EXE := $(suffix $(abspath $(JULIA))) + +# get compiler and linker flags. (see: `contrib/julia-config.jl`) +JULIA_CONFIG := $(JULIA) -e 'include(joinpath(Sys.BINDIR, Base.DATAROOTDIR, "julia", "julia-config.jl"))' -- +JULIA_LIBDIR := $(shell $(JULIA) -e 'println(joinpath(Sys.BINDIR, "..", "lib"))' --) +CPPFLAGS_ADD := +CFLAGS_ADD = $(shell $(JULIA_CONFIG) --cflags) +LDFLAGS_ADD = -lm $(shell $(JULIA_CONFIG) --ldflags --ldlibs) -ljulia-internal + +# get the JuliaC build script +JULIAC_BUILDSCRIPT := $(shell $(JULIA) -e 'print(joinpath(Sys.BINDIR, Base.DATAROOTDIR, "julia", "juliac", "juliac-buildscript.jl"))') + +#============================================================================= + +release: libNMFMerge-o.a + +$(BIN)/libNMFMerge-o.a: $(PKGDIR)/language_wrappers/lib.jl $(JULIAC_BUILDSCRIPT) + $(JULIA) -t 1 -J $(JULIA_LIBDIR)/julia/sys.$(SHLIB_EXT) --startup-file=no --history-file=no --project=$(PKGDIR)/language_wrappers/ --output-o $@ --output-incremental=no --strip-ir --strip-metadata --experimental --trim $(JULIAC_BUILDSCRIPT) $< --output-lib true $(BIN)/bindinginfo_libNMFMerge.log + +# check: $(BIN)/libNMFMerge$(EXE) +# $(JULIA) --depwarn=error $(SRCDIR)/trimming.jl $< + +clean: + -rm -f $(BIN)/libNMFMerge-o.a $(BIN)/bindinginfo_libNMFMerge.log + +.PHONY: release clean + +# Makefile debugging trick: +# call print-VARIABLE to see the runtime value of any variable +print-%: + @echo '$*=$($*)' diff --git a/language_wrappers/Project.toml b/language_wrappers/Project.toml new file mode 100644 index 0000000..7ed0fed --- /dev/null +++ b/language_wrappers/Project.toml @@ -0,0 +1,5 @@ +[deps] +NMFMerge = "9cc52eda-dfaf-4e21-aae3-9f26bed153a3" + +[sources] +NMFMerge = {path = ".."} diff --git a/language_wrappers/lib.jl b/language_wrappers/lib.jl new file mode 100644 index 0000000..29b886a --- /dev/null +++ b/language_wrappers/lib.jl @@ -0,0 +1,29 @@ +module NMFMergeLib + +using NMFMerge + +struct ReturnValue + niters::Int32 + converged::Bool + objvalue::Float64 +end + +struct CMatrix{T} <: AbstractMatrix{T} + data::Ptr{T} + rows::Int32 + cols::Int32 +end + +Base.@ccallable function nmfmerge_inplace(Wout::CMatrix{Float64}, Hout::CMatrix{Float64}, X::CMatrix{Float64}, ncomponents::Int32, tol::Float64, maxiter::Int32)::ReturnValue + Wout.rows == X.rows || throw(ArgumentError("Wout and X must have the same number of rows")) + Hout.cols == X.cols || throw(ArgumentError("Hout and X must have the same number of columns")) + W, H, X = unsafe_wrap(Array, Wout.data, (Wout.rows, Wout.cols)), + unsafe_wrap(Array, Hout.data, (Hout.rows, Hout.cols)), + unsafe_wrap(Array, X.data, (X.rows, X.cols)) + result = nmfmerge(X, ncomponents; tol_final=tol, maxiter) + W .= result.W + H .= result.H + return ReturnValue(result.niters, result.converged, result.objvalue) +end + +end