cmake 编译工程具有独特的优势,特别对于复杂的工程更是如此。利用matlab直接编译mex文件时,对于文件数据多的工程时,需要列举所有文件,并且要按照依赖关系排序,这些都是直接采用matalb编译mex的缺点。
下面通过一个简单的加法函数例子,说明如何利用cmake编译生成mex文件。如何对系统动态库进行设置,使matlab能够正常调用mex函数。
首先说明如何生成mex文件。
本例首先利用add.h、add.cpp文件编译生成add.so动态文件库,然后利用mian.cpp文件调用add.so库文件实现加法运算。本工程的结构如下图所示:
其中FindMatlab.cmake文件是寻找本机matlab头文件,库文件等相关路径信息的脚本,Matalbdef.def文件是指定函数接口方式采用matlab mex库文件形式,bin文件夹存放工程的mex文件,building文件夹存放camke工程文件。Matalbdef.def和FindMatlab.cmake文件可以在www.mathworks.com/matlabcentral/fileexchange/45522-mex-cmake下载。
工程根目录下的CMakeLists.txt文件如下:
cmake_minimum_required(VERSION 2.8)
project(ADD)
set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR})
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) # add FindMatlab module
add_definitions(/DMATLAB_MEX_FILE) #define matlab macros
add_definitions(/DMX_COMPAT_32)
find_package(Matlab REQUIRED)
IF(MATLAB_FOUND)
message(STATUS "MATLAB Found, MATLAB MEX will be compiled.")
add_subdirectory(src)
ELSE(MATLAB_FOUND)
MESSAGE("MATLAB not found...nothing will be built.")
ENDIF(MATLAB_FOUND)
该文件实现对matalb相关路径信息进行配置,CMAKE_INSTALL_PREFIX变量规定了编译完成后,执行make install命令后生成的mex文件转移到什么地方,该变量只是给出一个根目录,具体位置还要看CMakeLists.txt文件中如何写,如本例中给出下面的命令:
install(TARGETS ${CPP_FILE} DESTINATION ./bin)
最终mex文件被转移到 ${CMAKE_INSTALL_PREFIX}/bin目录下面。
src文件夹下的CMakeLists.txt文件如下,该文件给出库文件源文件和main文件位置,这两个顺序不能变,mian是依赖与库文件的,要先编译库文件,后编译mian文件。
add_subdirectory(add)
add_subdirectory(main)
add文件夹下的CMakeLists.txt文件如下,由于ubuntu系统下matlab只有动态文件库,所以这里只能生成动态库,这样才能和matlab mex函数进行配合使用。
include_directories(${PROJECT_SOURCE_DIR}/include)
aux_source_directory(. SRC_FILES)
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
add_library(add_lib SHARED ${SRC_FILES})
set_target_properties(add_lib PROPERTIES OUTPUT_NAME "add")
main文件夹下的CMakeLists.txt文件如下,该文件实现将动态库add.so封装到mex文件中的功能。其总include_directories指令要在add_library指令前面,这样才能事先指定mex依赖的库文件位置。最后的install将生成好的mex文件复制到指定位置。
# compile mex file
set(CPP_FILE main)
# set up matlab libraries
set(CPP_FILE_NAME ${CPP_FILE}.cpp)
include_directories(${MATLAB_INCLUDE_DIR} ${PROJECT_SOURCE_DIR}/include)
link_directories(${PROJECT_SOURCE_DIR}/lib)
add_library(${CPP_FILE} SHARED ${CPP_FILE_NAME} ${PROJECT_SOURCE_DIR}/Matlabdef.def)
target_link_libraries(${CPP_FILE} libadd.so ${MATLAB_LIBRARIES})
# 32-bit or 64-bit mex
if(WIN32)
if (CMAKE_CL_64)
set_target_properties(${CPP_FILE} PROPERTIES SUFFIX .mexw64)
else(CMAKE_CL_64)
set_target_properties(${CPP_FILE} PROPERTIES SUFFIX .mexw32)
endif(CMAKE_CL_64)
else(WIN32)
if (CMAKE_SIZEOF_VOID_P MATCHES "8")
set_target_properties(${CPP_FILE} PROPERTIES SUFFIX .mexa64 PREFIX "")
else(CMAKE_SIZEOF_VOID_P MATCHES "8")
set_target_properties(${CPP_FILE} PROPERTIES SUFFIX .mexglx PREFIX "")
endif (CMAKE_SIZEOF_VOID_P MATCHES "8")
endif(WIN32)
# install to /bin by default
install(TARGETS ${CPP_FILE} DESTINATION ./bin)
include文件夹下头文件add.h内容为
float add(float p1,float p2);
add文件夹下源文件add.cpp内容为
float add(float p1,float p2)
{
return p1+p2;
}
mian文件夹下main.cpp内容为
#include "mex.h"
#include"add.h"
void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
{
float a;
a=add(3,5);
mexPrintf("Hello World\n");
mexPrintf("%g\n",a);
}
cmake编译之前需要在系统变量中加入MATLAB_ROOT环境变量,该变量会在FindMatlab.cmake文件中使用,使该脚本文件能够找到matlab的头文件和库文件信息,对于本机加入MATLAB_ROOT环境变量语句如下:
export MATLAB_ROOT=/usr/local/MATLAB/R2014b
编译的结果如下:
make结果如下,工程中先编译了动态链接库文件libadd.so,ubuntu系统中库文件都会默认有前缀lib,该前缀不能去除,否则系统会出现找不动态链接的情况。
make install结果如下:
至此mex文件便生成完成。
配置系统动态库,matalb调用生成的main.mexa64函数
总的步骤是在系统某个位置保存我们生成的动态库文件和相应的头文件,并将该路径信息以系统变量的形式保存到系统中。下面是详细步骤
1).建立该文件夹/usr/local/mylib
本例中在 /usr/local下建立了mylib文件夹sudo mkdir /usr/local/mylib
2)在/etc/ld.so.conf.d文件夹下面建立mylib.conf 文件,并使其记录动态库的目录。
sudo gedit /etc/ld.so.conf.d/mylib.conf
文件中加入语句
/usr/local/mylib
3)在/usr/local/mylib文件夹下建立mypkgconfig文件夹,该文件夹下将会保存具体的动态库信息,如头文件、动态库文件
sudo mkdir /usr/local/mylib/mypkgconfig
该文件内容如下
# Package Information for pkg-config
prefix=/usr/local
exec_prefix=${prefix}
libdir=
includedir=${prefix}/myinclude
Name: MyLib
Description: lib created by myself
Version: 1.0
Libs: ${exec_prefix}/mylib/lib<span style="font-family:Liberation Serif, serif;">add</span>.so -lrt -lpthread -lm -ldl
Cflags: -I${includedir}
4)在/usr/local文件夹下建立myinclude文件夹,用来存放动态库头文件
sudo mkdir /usr/local/myinclude
5)将所建立库的头文件block.h,graph.h复制到/usr/local/myinclude目录下,下面的代码都是默认当前目录在文件所在目录下
sudo cp <span style="font-family:Liberation Serif, serif;">add</span>.h /usr/local/myinclude
6)将建立的动态库文件libadd.so移动到/usr/local/mylib文件夹下
sudo cp lib<span style="font-family:Liberation Serif, serif;">add</span>.so /usr/local/mylib
7)刷新缓冲器
sudo ldconfig
8)在开机启动时执行配置
sudo gedit /etc/bash.bashrc
在文件最后一行添加下面两行到文件的末尾并保存。
MY_PKG_CONFIG_PATH=$MY_PKG_CONFIG_PATH:/usr/local/mylib/mypkgconfig
exportMY_PKG_CONFIG_PATH
最后在matlab中运行结果如下图所示。