大话mysql5.7 移植(armhf 平台)

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!

接下来我们让我们开启正式的移植之旅。

1. 下载相关源码

1.1 下载mysql 的源码

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 版本的源码就可以了。

1.2  下载boost 库

mysql5.7.22 需要boost_1_59_0, 我们提供以下下载链接:https://www.boost.org/

boost 库是一个C++的扩展库。

1.3 下载ncurses 库

   链接如下:https://ftp.gnu.org/gnu/ncurses/

 

2. 编译X86 版本的mysql

我们是交叉编译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!

 

3. 交叉编译mysql

3.1 交叉编译通用配置

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 优先读取,进行配置。

3.2  mysql相关配置

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了。

3.3  mysql 交叉编译的其他修正

我们前面提到过,交叉编译时需要把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 提交的所有修改就是这篇文章上面描述的几个注意点。

3.4 配置编译

# 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 交叉编译的问题,欢迎留言,我看到后,一定会第一时间回复!

 

4. 配置/运行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

你可能感兴趣的:(应用,armlinux,ARM)