Android 交叉编译 Linux 可执行文件

前言

整理以前项目的时候发现以前做交叉编译,当时是交叉编译一个开源的c++项目到Android,直接使用NDK需要修改太多源码,本人对C也不是很熟悉,就研究了交叉编译。

本人电脑是 Ubuntu16.04,测试手机Android 8.0 系统

交叉编译工具链

安装 gcc:

sudo apt-get install arm-linux-gnueabi-gcc

安装g++

sudo apt-get install arm-linux-gnueabi-g++

安装cmake

sudo apt-get install cmake

Hello.c

#include   
int main()  
{  
printf("helloworld!\n");  
return 0;  
}  

生成ARM可执行文件

先使用gcc直接编译,后面使用cmake在做一次。

arm-linux-gnueabi-gcc hello.c -o hello -static 

当前目录下会生成一个名为hello的可执行文件,注意 -static 是一定要添加的

导入到设备

直接倒入到外置存储根目录:

adb push hello /sdcard/

此时shell进去还是无法运行。

在Android程序中调用

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        new Thread(() -> {
            CommandResult exec = ShellCommand.exec("cp /sdcard/hello /data/data/com.dome.hotfixdome/", false);
            Log.i(TAG, "run0: "+exec);
            CommandResult exec1 =ShellCommand.exec("chmod 751 /data/data/com.dome.hotfixdome/hello", false);
            Log.i(TAG, "run1: "+exec1);
            CommandResult exec2 = ShellCommand.exec("/data/data/com.dome.hotfixdome/hello", false);
            Log.i(TAG, "run2: "+exec2);
        }).start();
}        

上面代码直接写在MainActivity,部分代码解释:

  • ShellCommand.exec() 工具类,用来调用 Runtime.getRuntime().exec()并返回结果,后面会贴出

  • cp /sdcard/hello /data/data/com.dome.hotfixdome/ 复制hello到/data/data目录

  • chmod 751 /data/data/com.dome.hotfixdome/hello 设置hello可执行权限

  • /data/data/com.dome.hotfixdome/hello 运行可执行文件

日志输出:

04-08 15:01:08.829 I: run0: CommandResult{result=0, errorMsg='', successMsg=''}
04-08 15:01:08.842 I: run1: CommandResult{result=0, errorMsg='', successMsg=''}
04-08 15:01:08.849 I: run2: CommandResult{result=0, errorMsg='', successMsg='helloworld!'}

可以看到最后输出”helloworld!“

使用cmake编译

当时研究交叉编译就是因为所需要的开源项目是cmake编译的。但是如何在linux下编译生成Android可执行文件基本上没资料,前前后后搞了半个月才编译成功。

cmake_minimum_required(VERSION 2.8.12)
SET(CMAKE_SYSTEM_NAME Linux)

#指定交叉编译工具链
SET(CMAKE_C_COMPILER "arm-linux-gnueabi-gcc")
SET(CMAKE_CXX_COMPILER "arm-linux-gnueabi-g++")
#指定链接方式
SET(CMAKE_EXE_LINKER_FLAGS "-static")

add_executable(hello  src/hello.c) 

文件目录:
Android 交叉编译 Linux 可执行文件_第1张图片
编译:

  • 创建一个build目录
mkdir build
  • 进入build目录
cd build
  • cmake
cmake ..
  • 生成可执行文件
make

然后会在当前目录下生成可执行文件,其余步骤同上。

Android Shell 工具类

public class ShellCommand {
    private final static String COMMAND_SU = "su";
    private final static String COMMAND_SH = "sh";
    private final static String COMMAND_EXIT = "exit\n";
    private final static String COMMAND_LINE_END = "\n";


    @WorkerThread
    public static void exec(String... commands) {
        try {
            Process process = Runtime.getRuntime().exec(commands);
            process.waitFor();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 执行命令—单条
     */
    @WorkerThread
    public static CommandResult exec(String command, boolean isRoot) {
        String[] commands = {command};
        return exec(commands, isRoot);
    }

    /**
     * 执行命令-多条
     */
    @WorkerThread
    public static CommandResult exec(String[] commands, boolean isRoot) {
        CommandResult commandResult = new CommandResult();
        if (commands == null || commands.length == 0) {
            return commandResult;
        }
        Process process = null;
        DataOutputStream os = null;
        BufferedReader successResult = null;
        BufferedReader errorResult = null;
        StringBuilder successMsg;
        StringBuilder errorMsg;
        try {
            process = Runtime.getRuntime().exec(isRoot ? COMMAND_SU : COMMAND_SH);
            os = new DataOutputStream(process.getOutputStream());
            for (String command : commands) {
                if (command != null) {
                    os.write(command.getBytes());
                    os.writeBytes(COMMAND_LINE_END);
                    os.flush();
                }
            }
            os.writeBytes(COMMAND_EXIT);
            os.flush();
            commandResult.result = process.waitFor();
            //获取错误信息
            successMsg = new StringBuilder();
            errorMsg = new StringBuilder();
            successResult = new BufferedReader(new InputStreamReader(process.getInputStream()));
            errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));
            String s;
            while ((s = successResult.readLine()) != null) {
                successMsg.append(s);
            }
            while ((s = errorResult.readLine()) != null) {
                errorMsg.append(s);
            }
            commandResult.successMsg = successMsg.toString();
            commandResult.errorMsg = errorMsg.toString();
        } catch (Exception e) {
            Log.e(TAG, "exec: ", e);
        } finally {
            try {
                if (os != null) {
                    os.close();
                }
                if (successResult != null) {
                    successResult.close();
                }
                if (errorResult != null) {
                    errorResult.close();
                }
            } catch (IOException e) {
                Log.e(TAG, "exec: ", e);
            }
            if (process != null) {
                process.destroy();
            }
        }
        return commandResult;
    }

    private static final String TAG = "ShellCommand";
}
public class CommandResult {
    /**
     * 0 success
     * otherwise error
     */
    public int result = -1;
    public String errorMsg;
    public String successMsg;

    @Override
    public String toString() {
        return "CommandResult{" +
                "result=" + result +
                ", errorMsg='" + errorMsg + '\'' +
                ", successMsg='" + successMsg + '\'' +
                '}';
    }
}

你可能感兴趣的:(android)