Android 運行 C/C++程序 (使用 arm-linux-gcc 交叉編譯環境)

這個其實就是個人的一個小小的興趣,用C/C++寫一個小程序放在Android的系統中,然後用Java寫一個Android的UI程序來調用這個C/C++的程序。這裏總結了實現這個功能的一些步驟和遇到的問題。蠻有意思的。


這裏參考了下面兩篇博文,主要是關於搭建arm-linux-gcc交叉編譯環境的,非常有幫助,感謝他們的分享。

http://blog.csdn.net/super005/article/details/6369577

http://mawenhao19930620.blog.163.com/blog/static/128575361201212211291763/

http://www.cnblogs.com/huaping-audio/archive/2009/08/27/1555089.html


 

這裏主要分四步:

1)搭建一個交叉編譯環境,這裏用的是Ubuntu的虛擬機來編譯出一個可以在Android系統上運行的二進制文件;

2) 寫一個 hello.c 的測試用的C程序 ,並且把它編譯成可執行文件;

3)把可執行文件上傳到Android系統中,及一些注意事項。

4)寫一個Java的UI程序來調用這個測試的C程序。



第一步  搭建壞境

主要參考了上面兩個鏈接中的文章,簡單而非常有幫助。

這裏需要交叉編譯的主要原因是Android系統源於Linux但不同於Linux,Linux上的程序無法直接在Android上運行。需要重新編譯才行。Android設備主要基於 ARM的,在PC上的程序基於的X86的結構,這也導致了Linux下的程序必須重新編譯才能在Android下運行。

在兩篇文章中都提到了使用一個編譯工具

arm-none-linux-gnueabi

一個使用的是 2009 版本的,一個是2008版本的。

配置方式都是把目標壓縮文件Copy到一Linux的系統上,然後解壓縮,設置PATH,

使用arm-none-linux-gnueabi-gcc 命令編譯程序。

這裏保存一下兩個工具的下載地址

arm-2010.09-50-arm-none-linux-gnueabi

arm-2008q3-41-arm-none-linux-gnueabi


在Linux配置 PATH的方法 (Ubuntu)

1)  su nano ~/.bashrc

2)  在文件末尾添加如下的一行

export PATH=$PATH:/... .../... .../arm-2010.09-50/bin

3)  保存文件並退出

4)  運行命令 source ~/.bashrc

5)  當然可以用命令行驗證一下是否成功  arm-none-linux-gnueabi-gcc  --version。



第二步  編譯C程序

寫一個簡單的HelloWorld.c 的程序(最愛)。

  1. #include <stdio.h>  
  2. int main()  
  3. {  
  4.   int i=0;  
  5.   printf("hi ym012 %d/n",i);  
  6.   return;  
  7. }  

使用命令  arm-none-linux-gnueabi-gcc -static HelloWorld.c -o HelloWorld

這裏注意使用 -static 選項,測試時我沒有使用這個參數,結果編譯出來的程序在Android系統中是沒法運行的。



第三步  上傳C的可執行文件

把編譯好的HelloWorld程序使用 adb push 上傳的一個Android系統中。這裏測試時使用的是一個Android虛擬機,其中虛擬了一個 256M的sdcard。這裏把程序先上傳到sdcard有一個好處是基本不會失敗。

上傳程序後當然可以嘗試着在Android Shell 中運行編譯好的程序。

1)  使用 adb shell, 進入Android 的命令行。

2)  cd /mnt/sdcard 進入HelloWorld的存儲位置。

3)  ./HelloWorld 執行程序,


但如果嘗試在sdcard 中運行程序多半會遇到一個Permision Denied一個錯誤。

我們可以簡單嘗試使用 chmod 777 HelloWorld來修復它,但再次運行程序時多半還會失敗。

網上找了找原因,給出的解釋是Android不能修改 sdcard下 程序的權限,最簡單的老老實實把它複製到Android系統下的某個文件夾下吧。


4)  cp /mnt/sdcard/HelloWorld  /data/    複製文件到Android的data目錄下

5)  chmod 777 HelloWorld  修改權限

6)  ls -l 當然可以在查詢一下,但也不是必須的。

7)  ./HelloWorld  運行程序


這時基本已經可以了。

picture_1


如果交叉編譯出來的程序不正確在這裏是沒法運行的,出現 error:  magic 7F45  基本上就是交叉編譯出的問題了。

picture_err



第四步  使用Java 開發 UI

能在Android系統下把編譯好的C程序運行起來基本已經完成了 90%了,這裏使用Java 寫一個Android的 UI 只是爲了讓程序更好玩一些。

這裏主要使用的是 Progress 和 ProgressBuilder 的Java 的類庫。


程序實例:

MainActivity.java

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. package com.example.systeminformation;  
  2.   
  3.   
  4. import java.io.IOException;  
  5.   
  6. import android.os.Bundle;  
  7. import android.app.Activity;  
  8. import android.app.AlertDialog;  
  9. import android.content.Intent;  
  10. import android.view.View;  
  11. import android.widget.Button;  
  12.   
  13.   
  14. public class MainActivity extends Activity   
  15. {  
  16.   
  17.     private Button btnRunHello;  
  18.       
  19.     private Intent intent;  
  20.     @Override  
  21.     protected void onCreate(Bundle savedInstanceState)   
  22.     {  
  23.         super.onCreate(savedInstanceState);  
  24.         setContentView(R.layout.activity_main);  
  25.   
  26.   
  27.         btnRunHello = (Button) findViewById(R.id.id_run_hello);  
  28.           
  29.         btnRunHello.setOnClickListener(new View.OnClickListener()   
  30.         {  
  31.             @Override  
  32.             public void onClick(View arg0)   
  33.             {  
  34.                 CMDExecute m_Executor = new CMDExecute();  
  35.                   
  36.                 String m_strResult = "";  
  37.                 String arg[] = {"/data/hello"};  
  38.                 try   
  39.                 {  
  40.                     m_strResult = m_Executor.run(arg, "/data");  
  41.                 }   
  42.                 catch (IOException e)   
  43.                 {  
  44.                     e.printStackTrace();  
  45.                 }  
  46.                   
  47.                 new AlertDialog.Builder(MainActivity.this)  
  48.                  .setTitle("Run Hello")   
  49.                  .setMessage(m_strResult)  
  50.                     .setPositiveButton("確定"null)  
  51.                     .show();                      
  52.             }  
  53.         });  
  54.     }  
  55. }  


CMDExecute,java

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. package com.example.systeminformation;  
  2.   
  3. import java.io.File;  
  4. import java.io.IOException;  
  5. import java.io.InputStream;  
  6.   
  7. public class CMDExecute   
  8. {  
  9.     public synchronized String run(String[] cmd, String workdirectory) throws IOException  
  10.     {  
  11.         String result = "";  
  12.           
  13.         try  
  14.         {  
  15.             ProcessBuilder builder = new ProcessBuilder(cmd);  
  16.             if (workdirectory != null)  
  17.             {  
  18.                 builder.directory(new File(workdirectory));  
  19.                 builder.redirectErrorStream(true);  
  20.                   
  21.                 Process process = builder.start();  
  22.                 InputStream in = process.getInputStream();  
  23.                 byte[] re = new byte[1024];  
  24.                   
  25.                 while (in.read(re) != -1)  
  26.                 {  
  27.                     System.out.println(new String (re));  
  28.                     result = result + new String(re);  
  29.                 }  
  30.                 in.close();  
  31.             }  
  32.         }  
  33.         catch(Exception ex)  
  34.         {  
  35.             ex.printStackTrace();  
  36.         }  
  37.         return result;        
  38.     }  
  39. }  


運行結果: 

pic_result

發佈了4 篇原創文章 · 獲贊 15 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章