mysql 自从5.5 以后,使用cmake 作为它的编译框架。之前一直用autotools 进行编译,即configure & make & make install。为啥要用cmake, 主要原因是,它可以跨平台编译,不但可以用于linux, 还是用于windows。cmake 和Makefile 一样,在每个目录都有一个叫CMakeList.txt 的文件,这个文件控制着该目录的编译情况。CMakeList.txt 描述编译过程中的一些命令,参数,编译环境,和大量的配置变量, 所以你想一下子搞明白它的语法,是不可能的,只有在以后使用过程中不断地查它的帮助手册,来慢慢熟悉它。
X86版本的mysql 移植很简单,直接敲命令即可。也许,官方发布的mysql 主要为了X86 版本的编译,针对交叉编译,可能需要修改一些编译的规则,完善mysql 的编译规则,最终完成mysql 的交叉编译。关于如何交叉编译cmake 版本的mysql,下面的链接给出了各自的答案,有些可以编译出来,有些没办法编出来。在交叉编译之前,可以分别读下他们的文章,这样大概对mysql 的cmake 有所熟悉。
https://blog.csdn.net/fhyocean/article/details/74960005
https://blog.csdn.net/catemo/article/details/53136343
https://github.com/velarn/CrossCompliteArmMysql
在此声明一点,非常感谢这三篇文章的博主,不是他们的文章,我将不会产生下面的文章,他们的文章是我移植mysql 的启蒙老师,在此非常感谢他们!
But, If this is all, I will never do it agin!
接下来我们让我们开启正式的移植之旅。
mysql 的官方release 源码位于https://dev.mysql.com/downloads/mirrors/。
在这个链接中,随便选择一个网站,进行下载,就可以下载到官方的各种releasse 版本的源码。
不过,笔者有一个更好的推荐,那就是mysql 的官方github:https://github.com/mysql/mysql-server/tree/5.7
这个链接中源码是Orcale 官方关于mysql 的最新源码,同时修正了版本release 后发现的一些bug,所以用这个源码是bug最少的源码,请放心使用。 比如我们这次以mysql5.7.22 作为例,故下载5.7.22 版本的源码就可以了。
mysql5.7.22 需要boost_1_59_0, 我们提供以下下载链接:https://www.boost.org/
boost 库是一个C++的扩展库。
链接如下:https://ftp.gnu.org/gnu/ncurses/
我们是交叉编译ARM 版本的mysql, 为啥还要编译X86版本的呢? 有移植经验的同学会知道: 编译过程中要生成一些工具,并在编译的时候要执行。 mysql 也一样, 编译的时候需要执行以下6 个工具来完成编译:
1)extra/comp_err
2) scripts/comp_sql
3) sql/gen_lex_hash
4) sql/gen_lex_token
5) extra/protobuf/protoc
6) libmysql/libmysql_api_test
这6 个可执行程序是编译的中间工具,缺一不可。 否则,你总会发现会出现下面的情况,或者更诡异的现象:
/lib/ld-linux-armhf.so.3: No such file or directory.
刚开始你会以为这是链接时没有链接库文件, 去你的交叉编译连的sysroot 路径一看,有啊,最终发现是在执行时没有对应的库文件。 还有可能就是不能执行的二进制文件..... 所以在交叉编译前,这几个能在X86 端运行的中间工具要编译出来。
编译X86 版本的image 只需要做以下步骤即可:
1) apt-get install 安装ncurses 库
2) copy boots 库到mysql 路径下
3) 执行cmake 命令:
# cmake . -DENABLE_DOWNLOADS=1 -DDOWNLOAD_BOOST=1 -DWITH_BOOST=boost_1_59_0 -DCMAKE_INSTALL_PREFIX=${PWD}/out
DOWNLOAD_BOOST: 如果找不到boost 包,就直接下载;
WITH_BOOST:用于指定boost 包的源码路径 ;
CMAKE_INSTALL_PREFIX: 啥也不说了, 相当与autotools 时代configure 时的--prefix 参数,用以指定安装路径。
ENABLE_DOWNLOADS: 其他库不存在,就直接下载。
4) 编译 && 安装
X86 版本的基本配置不会有什么问题,很容易就配置 okay 了,然后执行以下命令,编译&& 安装
# make -j8 && make install
至此X86 版本的mysql 编译完成。这有啥难度, 还要专门写文章? young man, no hurry!
cmake 要做交叉编译,必须要有一个用于指定交叉编译链的配置文件,根据cmake 的官方描述,该内容大致如下demo:
################################################
####### General crosscompile toolchain file
################################################
SET(CMAKE_SYSTEM_NAME Linux)
SET(CMAKE_SYSTEM_PROCESSOR arm)
SET(CMAKE_CROSSCOMPILING 1)
SET(CMAKE_SYSROOT /opt/fsl-imx-x11/4.1.15-2.0.0/sysroots/cortexa9hf-neon-poky-linux-gnueabi)
SET(CMAKE_FIND_ROOT_PATH ${your_cmake_project_directory} /opt/fsl-imx-x11/4.1.15-2.0.0)
#LINK_DIRECTORIES(/opt/fsl-imx-x11/4.1.15-2.0.0/sysroots/cortexa9hf-neon-poky-linux-gnueabi)
SET(CMAKE_C_COMPILER arm-poky-linux-gnueabi-gcc)
SET(CMAKE_CXX_COMPILER arm-poky-linux-gnueabi-g++)
SET(CMAKE_C_COMPILER_ARG1 "-march=armv7-a -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a9 --sysroot=/opt/fsl-imx-x11/4.1.15-2.0.0/sysroots/cortexa9hf-neon-poky-linux-gnueabi")
SET(CMAKE_CXX_COMPILER_ARG1 "-march=armv7-a -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a9 --sysroot=/opt/fsl-imx-x11/4.1.15-2.0.0/sysroots/cortexa9hf-neon-poky-linux-gnueabi")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --sysroot=/opt/fsl-imx-x11/4.1.15-2.0.0/sysroots/cortexa9hf-neon-poky-linux-gnueabi")
SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --sysroot=/opt/fsl-imx-x11/4.1.15-2.0.0/sysroots/cortexa9hf-neon-poky-linux-gnueabi")
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
上面基本上是一个通用的用于交叉编译的cmake配置模板,也就是说,你要交叉编译一个cmake 工程, 关于交叉编译器,你只需要配置以上内容就足够了.
CMAKE_SYSTEM_NAME: target系统的名字。该变量被设置,CMAKE_CROSSCOMPILING 将会自动被设置为true。 所以, 为了使能cmake 的交叉编译, 你必须显式地指定这个变量。
CMAKE_SYSTEM_PROCESSOR:cmake 中指定系统使用的处理器, 这个是optional, 指不指定都可以;
CMAKE_SYSROOT: 不用说了,交叉编译器的sysroot;
CMAKE_FIND_ROOT_PATH: cmake 查找所有头文件,library,其他程序的root路径,这个是交叉编译必须的。如果不指定,cmake 一直会在开发机系统的root路径中查找,你觉得不指定,能编译成功么? 相当关键的cmake 变量;
CMAKE_C_COMPILER && CMAKE_CXX_COMPILER : 这个不用介绍了吧;
CMAKE_C_COMPILER_ARG1 && CMAKE_CXX_COMPILER_ARG1: C 和C++ 编译的编译flags,有些编译器不指定这个,连最简单的helloldworld都编译不过。所以最好能够指定;
CMAKE_EXE_LINKER_FLAGS && CMAKE_MODULE_LINKER_FLAGS :
这两个是链接时的参数,可以不指定,并不影响。
CMAKE_FIND_ROOT_PATH_MODE_PROGRAM: 在刚才定义的root 路径列表中查找某个可执行程序, 交叉编译时,设定为NEVER 表示从来不再此查找;
CMAKE_FIND_ROOT_PATH_MODE_LIBRARY: 在刚才定义的root 路径列表中查找某个library, 交叉编译时,设定为ONLY 表示只从这里查找;
CMAKE_FIND_ROOT_PATH_MODE_INCLUDE && CMAKE_FIND_ROOT_PATH_MODE_PACKAGE : 同于上面的描述,交叉编译时,设定为ONLY。
假定以上的配置放在一个叫cross-compile.cmake 中, 用cmake 配置时,敲入以下命令apply该配置:
# cmake . -DCMAKE_TOOLCHAIN_FILE=${cross-compile-path}/cross-compile.cmake
CMAKE_TOOLCHAIN_FILE: 指定交叉编译链的配置文件, 该变量指定的文件会被cmake 优先读取,进行配置。
mysql 的配置,如下所示:
################################################################
####### The special configuration MACRO for mysql
################################################################
SET(WITH_UNIT_TESTS OFF) ## disable unit_test
SET(DEFAULT_CHARSET utf8) ## the default charset
SET(DEFAULT_COLLATION utf8_general_ci)
SET(EXTRA_CHARSETS all) ## Which extra character sets to include:
SET(STACK_DIRECTION 1) ## Stack grows direction
## If LOAD DATA LOCAL is disabled, either in the server or the client, a client that attempts
## to issue such a statement receives the following error message:
## ERROR 1148: The used command is not allowed with this MySQL version
SET(ENABLED_LOCAL_INFILE 1)
#SET(WITH_EMBEDDED_SERVER TRUE)
SET(HAVE_LLVM_LIBCPP OFF)
SET(HAVE_FALLOC_PUNCH_HOLE_AND_KEEP_SIZE 1)
SET(HAVE_IB_GCC_SYNC_SYNCHRONISE 1)
SET(HAVE_IB_GCC_ATOMIC_THREAD_FENCE 1)
SET(HAVE_IB_GCC_ATOMIC_COMPARE_EXCHANGE 1)
SET(HAVE_IB_ATOMIC_PTHREAD_T_GCC 1)
SET(HAVE_IB_LINUX_FUTEX 1)
SET(HAVE_GCC_ATOMICS_WITH_ARCH_FLAG 1)
SET(HAVE_FUNC_IN_CXX 1)
SET(HAVE___BUILTIN_FFS 1)
IF(CMAKE_COMPILER_IS_GNUCC)
SET(HAVE_C_FLOATING_POINT_FUSED_MADD 1)
ENDIF()
IF(CMAKE_COMPILER_IS_GNUCXX)
SET(HAVE_CXX_FLOATING_POINT_FUSED_MADD 1)
ENDIF()
IF(CMAKE_COMPILER_IS_GNUCC)
SET(HAVE_C_SHIFT_OR_OPTIMIZATION_BUG 1)
ENDIF()
IF(CMAKE_COMPILER_IS_GNUCXX)
SET(HAVE_CXX_SHIFT_OR_OPTIMIZATION_BUG 1)
ENDIF()
HAVE_LLVM_LIBCPP 及其以上内容就不再详解了,看下英文注释就okay了。
我们详细讲解它以下的内容的,为什么要做这样的配置? 这些东东都是啥东西?
其实一切都源于在编译中的错误“#error Unsported Platform”, 有人因此修改了mysql 的源代码,跳过了这个问题,编译成功!其实后来发现,这种做法并不正确。下面我们来一一分析:
先看下,这个错误从哪里打印出来的:
innobase/include/os0atomic.ic
#ifdef _WIN32
............
#elif defined(HAVE_IB_GCC_ATOMIC_COMPARE_EXCHANGE)
.....
UNIV_INLINE
lock_word_t
os_atomic_test_and_set(
volatile lock_word_t* ptr,
lock_word_t new_val)
{
lock_word_t ret;
/* Silence a compiler warning about unused ptr. */
(void) ptr;
#if defined(__powerpc__) || defined(__aarch64__)
__atomic_exchange(ptr, &new_val, &ret, __ATOMIC_SEQ_CST);
#else
__atomic_exchange(ptr, &new_val, &ret, __ATOMIC_RELEASE);
#endif
return(ret);
}
#elif defined(IB_STRONG_MEMORY_MODEL)
.........
#else
#error "Unsupported platform"
#endif /* _WIN32 */
由此可见,如果定义了_WIN32 , HAVE_IB_GCC_ATOMIC_COMPARE_EXCHANGE 或者IB_STRONG_MEMORY_MODEL 中的一个,就会定义一些mysql 编译必须的一些函数,否则就会打印#error "Unsupported platform" 的编译错误。 网上上这里没有关于arm 版本的定义,所以通过修改源码跳过了这个。
其实我们从上面可以看出有这么个宏:
#if defined(__powerpc__) || defined(__aarch64__)
#esle
........ // maybe for arm
#endif
__aarch64__ 指的是64 bit 的ARM。 尼玛,64位的arm都有,mysql 还能不提供32 bit 的arm 么!#else 后面的应该就是32 位arm 的定义了。
再看这个对应的判断宏是HAVE_IB_GCC_ATOMIC_COMPARE_EXCHANGE, 既然mysql 有关于arm的定义,为啥这个宏没有被定义呢?
最终搜到这个宏定义的cmake 脚本:
innobase/innodb.cmake +178
IF(NOT MSVC)
# either define HAVE_IB_GCC_ATOMIC_BUILTINS or not
IF(NOT CMAKE_CROSSCOMPILING)
CHECK_C_SOURCE_RUNS(
"#include
int main()
{
__sync_synchronize();
return(0);
}"
HAVE_IB_GCC_SYNC_SYNCHRONISE
)
CHECK_C_SOURCE_RUNS(
"#include
int main()
{
__atomic_thread_fence(__ATOMIC_ACQUIRE);
__atomic_thread_fence(__ATOMIC_RELEASE);
return(0);
}"
HAVE_IB_GCC_ATOMIC_THREAD_FENCE
)
CHECK_C_SOURCE_RUNS(
"#include
int main()
{
unsigned char a = 0;
unsigned char b = 0;
unsigned char c = 1;
__atomic_exchange(&a, &b, &c, __ATOMIC_RELEASE);
__atomic_compare_exchange(&a, &b, &c, 0,
__ATOMIC_RELEASE, __ATOMIC_ACQUIRE);
return(0);
}"
HAVE_IB_GCC_ATOMIC_COMPARE_EXCHANGE
)
ENDIF()
IF(HAVE_IB_GCC_SYNC_SYNCHRONISE)
ADD_DEFINITIONS(-DHAVE_IB_GCC_SYNC_SYNCHRONISE=1)
ENDIF()
IF(HAVE_IB_GCC_ATOMIC_THREAD_FENCE)
ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_THREAD_FENCE=1)
ENDIF()
IF(HAVE_IB_GCC_ATOMIC_COMPARE_EXCHANGE)
ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_COMPARE_EXCHANGE=1)
ENDIF()
搜索整个源码路径,只有该文件的178 行定义了HAVE_IB_GCC_ATOMIC_COMPARE_EXCHANGE, 其他地方没人定义。 再看看上面的代码:
CHECK_C_SOURCE_RUNS(
什么? 要检测这个C 代码的运行? 交叉编译的程序怎么可能在host 机器上运行呢? 当然上面的代码段没让它运行, 这就糟糕了, 交叉编译器实际上是支持这些功能的(已经一一验证过),但因为无法运行在host上,而被判定为不支持这种特性,这太不公平了吧!所以这就是交叉编译老是出错,camke配置也会出错的根本原因所在。
为了解决这一问题,你必须用你的交叉编译器分别一一验证上面所列的宏是不是支持。 即现编译这个宏对应的检测C代码,然后copy到你的板子上运行,如果okay,就把这些宏手动在配置文件中打开。上面我们列出的宏,就是通过这样的方式一一判断出来的。
同时 要记得给CHECK_C_SOURCE_RUNS 函数,加上交叉编译的判断,即
IF(NOT CMAKE_CROSSCOMPILING)
CHECK_C_SOURCE_RUNS....ENDIF()
如此, 便修正了unsported platform 相关的issue了。
我们前面提到过,交叉编译时需要把6 个中间工具copy 到对应的目录,并touch 它,然后进行编译。 这样比较麻烦的是,当你make clean 后, 有得重新copy && touch 它。这是比较麻烦的,为了修改这一点,我们直接搜索定义这个命令的CMakeList.txt.
libmysql/CMakeLists.txt
# Verify that libmysql_api_test runs OK
ADD_CUSTOM_COMMAND(TARGET libmysql_api_test POST_BUILD
COMMAND libmysql_api_test ## 改为 /usr/bin/libmysql_api_test
> ${CMAKE_CURRENT_BINARY_DIR}/libmysql_api_test.out
)
将命令改到/usr/bin 下,这样就不用每次clean 后都都copy && touch 了。我们只要把X86 版本的6个命令都copy 到/usr/bin/下, 然后
一一按照上面的逻辑修改这6个命令的CMakeList.txt.
$ cp extra/comp_err /usr/bin/
$ cp scripts/comp_sql /usr/bin/
$ cp sql/gen_lex_hash /usr/bin/
$ cp sql/gen_lex_token /usr/bin/
$ cp extra/protobuf/protoc /usr/bin/
$ cp libmysql/libmysql_api_test /usr/bin/
至此,这个issue 就解决了。
详细细节可以参考这个github 的链接:https://github.com/jwzl/mysql-server/tree/5.7
jwzl 提交的所有修改就是这篇文章上面描述的几个注意点。
# cmake . -DENABLE_DOWNLOADS=1 -DDOWNLOAD_BOOST=1 -DWITH_BOOST=boost_1_59_0 -DCMAKE_INSTALL_PREFIX=${PWD}/out -DCMAKE_TOOLCHAIN_FILE=./imx.cmake -DCURSES_LIBRARY=${PWD}/ncurses-5.9/out/lib -DCURSES_INCLUDE_PATH=${PWD}/out/include
toolchain file 为imx.cmake, 就是包含上面描述的所有配置的文件,可参考这里。
CURSES 库是要预先编译的,在编译mysql 前就要编译好,假定你已经编译okay。CURSES_LIBRARY && CURSES_INCLUDE_PATH 指定了编译好的CURSES 库/头文件的具体位置。
执行以上命令,就可以完成cmake 的配置。
然后执行
make && make install
如果你的电脑不行的话, 建议最好用make 不要用make -j4或make -j8. 笔者是i5的处理器,编到一般,电脑就卡死了。
最后,如果你遇到mysql 交叉编译的问题,欢迎留言,我看到后,一定会第一时间回复!
编译完成后,将编译好的目录copy到device 的/usr/local 下,执行以下脚本,即可完成基本配置:
#!/bin/bash
MYSQL_BASE=/usr/local/mysql
echo "Setup the mysql-5.7.23....."
echo "Create the data path ${MYSQL_BASE}/data..."
mkdir -p ${MYSQL_BASE}/data
echo "Initailize the data directory and create the MySQL grant tables"
${MYSQL_BASE}/bin/mysqld --user=root --basedir=${MYSQL_BASE} --datadir=${MYSQL_BASE}/data --initialize-insecure ##--initialize
echo "copy mysqld config file to /etc/ "
cp my.cnf /etc/my.cnf
echo "Create link to /usr/bin"
ln -s ${MYSQL_BASE}/bin/mysqld /usr/bin/mysqld
ln -s ${MYSQL_BASE}/bin/mysql /usr/bin/mysql
ln -s ${MYSQL_BASE}/bin/my_print_defaults /usr/bin/my_print_defaults
ln -s ${MYSQL_BASE}/bin/mysqladmin /usr/bin/mysqladmin
ln -s ${MYSQL_BASE}/bin/mysqldump /usr/bin/mysqldump
echo "Starting and Stopping MySQL Automatically.... "
cp ${MYSQL_BASE}/support-files/mysql.server /etc/init.d/mysqld
/usr/sbin/update-rc.d mysqld defaults 98
echo "No passwd for mysql, you can use the following command to login: "
echo "mysql -u root --skip-password "
echo "[Done]"
exit 0;
脚本中涉及到my.conf, 你可以按照自己需求进行配置,下面给出一个demo:
########################################################
###### mysql configure file
########################################################
[mysqld]
user=root
port=3306
datadir=/usr/local/mysql/data
basedir=/usr/local/mysql
socket=/tmp/mysql.sock
pid-file=/var/run/mysqld.pid
general-log-file=/var/log/mysqld.log
slow-query-log-file=/var/log/mysqld.log
log-error=/var/log/mysqld.log
[client]
port=3306
socket=/tmp/mysql.sock
通过以上步骤,就完成了相关的配置,接下来就可以直接运行mysql 客户端进行相关测试了。
至此,就完成了mysql 移植的相关描述,希望对你有所帮助。
参考:https://dev.mysql.com/doc/refman/5.7/en/source-configuration-options.html