1.本文章遵从” 署名-非商业性使用 2.5 中国大陆 (CC BY-NC 2.5 CN)” 2. 转载或引用本文档中的内容须注明 “资料来源:HB@ Technical Document” 字样 |
Sg3_utils包含各种可以从用户空间发命令到scsi设备, 这篇文章主要告诉大家如何移植sg3_utils到ARM平台上。 之前我们主要用sg3_utils是在台式机或者直接复制它到目标机上去编译, 但对于大多数嵌入式设备来说, 我们需要交叉编译,尤其是对于android系统, 如果external下面没有所需要的工具包时, 我们必须对它进行交叉编译。为什么要把sg3-utils的交叉编译写一篇文章呢?只要是在我自己交叉编译的过程中,发现了一些问题,这里只是作一个总结,以帮助后来者少走弯路。
Sg3_utils的官网是在http://sg.danny.cz/sg/sg3_utils.html,你可以从这里读取第一手的关于sg3_utils的介绍, 我在这里就不啰嗦了。在这个页面的最下方有它的下载地址。对于熟悉github的朋友可以用git clone下载, 你也可以下载压缩版本的。
其中要说明的是,上面两个github的下载地址, 一个是来此SUSE公司的Hannes Reinecke, 另一个是来此SDC的Bart Van Assche, 他根据自己的需求有可能会在各自的分支上加入一些自己的应用,anyway, 这两个你可以认选一个,eg”
Git clone https://github.com/bvanassche/sg3_utils.git
注: 你也可以从我个人的github上下载:
https://github.com/beanhuo/sg3_utils.git sg3_utils-1.43-for-android
这里要说明的是,如果你用linaro的gcc,编译出的来ELF可执行文件,所需要的interpreter的地址是/lib/ld-linux-aarch64.so,而android的interpreter是/system/bin/linker6。你可以把sg3_utils放到external下去编译,但这又需要一些时间。我的方法是构建自己的standalone toolchain来编译。
编译之前我们来下载NDK:
https://developer.android.com/ndk/downloads/older_releases.html#ndk-15c-downloads
这里有好多版本,我建议大家还是下载最新的版本,因为fix了一些之前版本的bug,相对稳定。
如果你用老一版本,很有可能在编译时,会出现下面的问题1:
./include/sg_linux_inc.h:14:25: fatal error: scsi/sg.h: No such file or directory #include <scsi/sg.h> |
他这这里描述的问题是一样的:https://karkhaz.github.io/tuscan/android/sg3_utils.html#162
具体为什么会出现上面的原因,这里我们就不多说了, 我们的最终目的是要编译通过。
OK,我这里下载的是Android NDK, Revision 15c (July 2017),一个最新的版本。
它是一个zip格式的压缩文件,没关系linux可以解压任何格式的压缩文件,只要你想的到。
unzipandroid-ndk-r15c-linux-x86_64.zip
解压完, 我们获得一个android-ndk-r15c的文件夹,它里面就是NDK的源文件。
关于如何创建standalone toolchain网上有好多的介绍,如https://gist.github.com/Tydus/11109634。
你可以安照上面的去做,但我不知道在编译的时候会出现什么问题,这里我只说我自己的,如下:
android-ndk-r15/build/tools/make_standalone_toolchain.py \
--arch arm64 --api 26 --install-dir/ubuntu/crosstools/my-android-arm64-toolchain
这里要想说的,不要用make-standalone-toolchain.sh去创建,这之前是用它去的,但发现会出现如下的问题:
./libcrypto.so: error: undefined reference to 'stdin'
./libcrypto.so: error: undefined reference to 'signal'
./libcrypto.so: error: undefined reference to 'tcsetattr'
./libcrypto.so: error: undefined reference to 'tcgetattr'
collect2: error: ld returned 1 exit status
同时也不要用--deprecated-headers选项,因为如果加了它,上面的问题1会出现。OK.
经过上面的命令后,会在你所指定的目录下出现我们想要的standalone toolchain:
root@bean-ubuntu:/ubuntu/crosstools/my-android-arm64-toolchain# ls drwxr-xr-x 5 root root 4096 dec 11 22:35 aarch64-linux-android -rw-r--r-- 1 root root 11 júl 21 11:03 AndroidVersion.txt drwxr-xr-x 10 root root 4096 dec 11 22:35 bin -rw-r--r-- 1 root root 18002 júl 21 11:04 COPYING -rw-r--r-- 1 root root 35147 júl 21 11:04 COPYING3 -rw-r--r-- 1 root root 7639 júl 21 11:04 COPYING3.LIB -rw-r--r-- 1 root root 26527 júl 21 11:04 COPYING.LIB -rw-r--r-- 1 root root 3324 júl 21 11:04 COPYING.RUNTIME drwxr-xr-x 4 root root 4096 dec 11 22:35 include drwxr-xr-x 7 root root 4096 dec 11 22:35 lib drwxr-xr-x 3 root root 4096 dec 11 22:35 lib64 drwxr-xr-x 3 root root 4096 dec 11 22:35 libexec -rw-r--r-- 1 root root 0 júl 21 11:03 MODULE_LICENSE_BSD_LIKE -rw-r--r-- 1 root root 0 júl 21 11:04 MODULE_LICENSE_GPL -rw-r--r-- 1 root root 0 júl 21 11:03 MODULE_LICENSE_MIT -rw-r--r-- 1 root root 125319 júl 21 11:08 NOTICE drwxr-xr-x 5 root root 4096 dec 11 22:35 prebuilt_include -rw-r--r-- 1 root root 4465 júl 21 11:08 repo.prop drwxr-xr-x 5 root root 4096 dec 11 22:35 share drwxr-xr-x 3 root root 4096 júl 21 11:04 sysroot drwxr-xr-x 7 root root 4096 dec 11 22:35 test drwxr-xr-x 4 root root 4096 dec 11 22:35 tools |
1. 申明你的交叉编译工具的路径:
exportPATH=$PATH:/home/ubuntu/crosstools/my-android-arm64-toolchain/bin
2. Configure
./configure CFLAGS=-static --prefix=/home/sg3_utils/out/ \ --host=aarch64-linux-android LD=aarch64-linux-android-ld CC=aarch64-linux-android-gcc |
一般上面的configure命令不会出错,这里是用GNU automake来去根据你的配制来生成makefile文件, 关于GNU automake我会写一篇专问的文章。
3. Make
当make时这里有一个小问题,会有下面的问题:
Making all in src make[2]: Entering directory '/home/workspace/micron/00_job_EBU/06_hikey960/source_code/android/external/sg3_utils/src' /bin/sh ../libtool --tag=CC --mode=link aarch64-linux-android-gcc -Wall -W -static -o sgp_dd sgp_dd.o ../lib/libsgutils2.la -lpthread -lm libtool: link: aarch64-linux-android-gcc -Wall -W -o sgp_dd sgp_dd.o ../lib/.libs/libsgutils2.a -lpthread -lm /home/ubuntu/crosstools/my-android-arm64-toolchain/bin/../lib/gcc/aarch64-linux-android/4.9.x/../../../../aarch64-linux-android/bin/ld: cannot find -lpthread collect2: error: ld returned 1 exit status Makefile:990: recipe for target 'sgp_dd' failed make[2]: *** [sgp_dd] Error 1 make[2]: Leaving directory '/home/workspace/micron/00_job_EBU/06_hikey960/source_code/android/external/sg3_utils/src' Makefile:401: recipe for target 'all-recursive' failed make[1]: *** [all-recursive] Error 1 make[1]: Leaving directory '/home/workspace/micron/00_job_EBU/06_hikey960/source_code/android/external/sg3_utils' Makefile:333: recipe for target 'all' failed make: *** [all] Error 2 |
如果去src/Makefile,对于sgp_dd.c的编译,多了一个-lpthread,
sgp_dd_LDADD = ../lib/libsgutils2.la -lpthread |
网上有好多版本的说法,因为我不需要sgp_dd这个工具, 所以这里我直接注消掉-lpthread,
sgp_dd_LDADD = ../lib/libsgutils2.la // -lpthread
同时也要注消掉在sgp_dd.c 中对于pthread_cancel的调用。
1632 // status = pthread_cancel(sig_listen_thread_id); 1633 if (0 != status) err_exit(status, "pthread_cancel"); |
主要原因是,android Bionic C library是不支持pthread_cancel,我们可以用signal来取代pthread_cancel.具体patch如下, 你也可以从我的github上下载fixed 版本。
---
configure | 30 ++++++++++++++++++++++++++++++
configure.ac | 6 ++++++
src/Makefile.am | 4 ++++
src/sgp_dd.c | 17 +++++++++++++++++
4 files changed, 57 insertions(+)
diff --git a/configure b/configure
index 9958be2..d9f23f2 100755
--- a/configure
+++ b/configure
@@ -635,6 +635,8 @@ ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS
+OS_ANDROID_FALSE
+OS_ANDROID_TRUE
OS_WIN32_CYGWIN_FALSE
OS_WIN32_CYGWIN_TRUE
OS_WIN32_MINGW_FALSE
@@ -12292,6 +12294,21 @@ _ACEOF
case "${host}" in
+ *-*-android*)
+
+cat >>confdefs.h <<_ACEOF
+#define SG_ON_ANDROID 1
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define SG_LIB_LINUX 1
+_ACEOF
+
+ os_cflags=''
+
+ os_libs=''
+ ;;
*-*-linux-gnu*)
cat >>confdefs.h <<_ACEOF
@@ -12428,6 +12445,14 @@ else
OS_WIN32_CYGWIN_FALSE=
fi
+ if echo $host_os | grep 'android' > /dev/null; then
+ OS_ANDROID_TRUE=
+ OS_ANDROID_FALSE='#'
+else
+ OS_ANDROID_TRUE='#'
+ OS_ANDROID_FALSE=
+fi
+
# Check whether --enable-linuxbsg was given.
if test "${enable_linuxbsg+set}" = set; then :
@@ -12624,6 +12649,10 @@ if test -z "${OS_WIN32_CYGWIN_TRUE}" && test -z "${OS_WIN32_CYGWIN_FALSE}"; then
as_fn_error $? "conditional \"OS_WIN32_CYGWIN\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi
+if test -z "${OS_ANDROID_TRUE}" && test -z "${OS_ANDROID_FALSE}"; then
+ as_fn_error $? "conditional \"OS_ANDROID\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO"
+5 fi
: "${CONFIG_STATUS=./config.status}"
ac_write_fail=0
@@ -14211,6 +14240,7 @@ $as_echo X"$file" |
cat <<_LT_EOF >> "$cfgfile"
#! $SHELL
# Generated automatically by $as_me ($PACKAGE) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
# NOTE: Changes made to this file will be lost: look at ltmain.sh.
# Provide generalized library-building support services.
diff --git a/configure.ac b/configure.ac index 6c35d1a..cef0686 100644
--- a/configure.ac
+++ b/configure.ac
@@ -37,6 +37,11 @@ AC_CANONICAL_HOST
AC_DEFINE_UNQUOTED(SG_LIB_BUILD_HOST, "${host}", [sg3_utils Build Host])
case "${host}" in
+ *-*-android*)
+ AC_DEFINE_UNQUOTED(SG_ON_ANDROID, 1, [sg3_utils on android])
+ AC_DEFINE_UNQUOTED(SG_LIB_LINUX, 1, [sg3_utils on linux])
+ AC_SUBST([os_cflags], [''])
+ AC_SUBST([os_libs], ['']) ;;
*-*-linux-gnu*)
AC_DEFINE_UNQUOTED(SG_LIB_LINUX, 1, [sg3_utils on linux])
AC_SUBST([os_cflags], ['']) @@ -79,6 +84,7 @@ AM_CONDITIONAL(OS_OSF, [echo $host_os | grep '^osf' > /dev/null]) AM_CONDITIONAL(OS_SOLARIS, [echo $host_os | grep '^solaris' > /dev/null]) AM_CONDITIONAL(OS_WIN32_MINGW, [echo $host_os | grep '^mingw' > /dev/null]) AM_CONDITIONAL(OS_WIN32_CYGWIN, [echo $host_os | grep '^cygwin' > /dev/null])
+AM_CONDITIONAL(OS_ANDROID, [echo $host_os | grep 'android' >
+/dev/null])
AC_ARG_ENABLE([linuxbsg],
AC_HELP_STRING([--disable-linuxbsg], [ignore linux bsg (sgv4) if present]), diff --git a/src/Makefile.am b/src/Makefile.am index 1012a78..daada79 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -86,7 +86,11 @@ sg_modes_LDADD = ../lib/libsgutils2.la @os_libs@
sg_opcodes_LDADD = ../lib/libsgutils2.la @os_libs@
+if OS_ANDROID
+sgp_dd_LDADD = ../lib/libsgutils2.la @os_libs@ else
sgp_dd_LDADD = ../lib/libsgutils2.la @os_libs@ -lpthread
+endif
sg_persist_LDADD = ../lib/libsgutils2.la @os_libs@
diff --git a/src/sgp_dd.c b/src/sgp_dd.c index e154555..d59167c 100644
--- a/src/sgp_dd.c
+++ b/src/sgp_dd.c
@@ -1121,6 +1121,11 @@ process_flags(const char * arg, struct flags_t * fp)
return 0;
}
+void
+thread_exit_handler(int sig)
+{
+ pthread_exit(0);
+}
#define STR_SZ 1024
#define INOUTF_SZ 512
@@ -1147,6 +1152,14 @@ main(int argc, char * argv[])
int in_sect_sz, out_sect_sz, status, n, flags;
void * vp;
char ebuff[EBUFF_SZ];
+#if SG_ON_ANDROID
+ struct sigaction actions;
+ memset(&actions, 0, sizeof(actions));
+ sigemptyset(&actions.sa_mask);
+ actions.sa_flags = 0;
+ actions.sa_handler = thread_exit_handler;
+ sigaction(SIGUSR1,&actions,NULL);
+#endif
memset(&rcoll, 0, sizeof(Rq_coll));
rcoll.bpt = DEF_BLOCKS_PER_TRANSFER; @@ -1629,7 +1642,11 @@ main(int argc, char * argv[])
}
}
+#if SG_ON_ANDROID
+ status = pthread_kill(sig_listen_thread_id, SIGUSR1); #else
status = pthread_cancel(sig_listen_thread_id);
+#endif
if (0 != status) err_exit(status, "pthread_cancel");
if (STDIN_FILENO != rcoll.infd)
close(rcoll.infd);
--
2.7.4
4. Make install
经过make install之前,我会在out目录下得到我们所要的目标文件,这时只要把bin下的ELF文件,根据你的需要adb push到你的android目标板上就可以了。
经过上面的各个步骤之后, 我们有了ELF文件,但对新版本的android,对于在external之外编译的ELF可执行文件,会出现“onlyposition independent executables (-fPIE) are supported”
加入LOCAL_CFLAGS += -fPIE
LOCAL_LDFLAGS += -fPIE -pie
对于直接使用gcc的,可以直接加在CFLAGS中加-fPIE -pie就可以了