在android中如何编译连接 .c 的可执行文件

本文介绍如何在Android环境中搭建简单的测试应用,包括创建项目、编写测试代码、编译及运行等步骤。通过示例展示了如何读取电池容量,并控制显示模式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 在./development目录下创建一目录 如:myhello
2. 进入hello目录,在其下编写自己的.c文件,如: myhello.c
    #include <stdio.h>
    int main()
    {
        printf("hello world\n");
        exit(0);
        //return 0;                       
    }
3. 在hello目录中,编写Android.mk, 内容如下:
    LOCAL_PATH:= $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE := myhelloworld
    LOCAL_SRC_FILES := myhello.c
    LOCAL_MODULE_TAGS := optional
    include $(BUILD_EXECUTABLE)
4. 回到Android源代码顶层目录,进行编译,make myhelloworld
5. 生成的可执行文件位于:out/target/product/lotus/system/bin/ 目录下
6. adb push 到手机 /data 目录下,然后进入adb shell,到data目录下,执行./myhelloworld 皆可

手动编译连接【arm-eabi-gcc 的目录随andorid的版本而有变化,还有就是需要链接的文件如果比较多时,需要很多-l 就很麻烦了
7、编译成目标文件:
   #$(yourAndroid)/prebuilt/linux-x86/toolchain/[arm-eabi-4.2.1]/bin/arm-eabi-gcc -I bionic/libc/arch-arm/include/ -I bionic/libc/include -I bionic/libc/kernel/common -I bionic/libc/kernel/arch-arm -g -c helloworld.c  -o hello.o
8、生成可执行代码:
   #$(yourAndroid)/prebuilt/linux-x86/toolchain/[arm-eabi-4.2.1]/bin/arm-eabi-gcc -nostdlib -Bdynamic -Wl,-T,build/core/armelf.x -Wl,-dynamic-linker,/system/bin/linker -Wl,--gc-sections -Wl,-z,nocopyreloc -o helloworld -Lout/target/product/[generic]/obj/lib -Wl,-rpath-link=out/target/product/[generic]/obj/lib -lc hello.o -entry=main

    其中[ ]中部分根据实际情况修改


**************************************************

实验:

1. 建目录(my android)/development/test, 在该目录下新建 Android.mk和fb_test.c文件

2. Android.mk文件

LOCAL_PATH:= $(call my-dir)                                                     
include $(CLEAR_VARS)                                                           
LOCAL_MODULE := myfbtest                                                        
LOCAL_SRC_FILES := fb_test.c                                                    
LOCAL_MODULE_TAGS := optional                                                   
include $(BUILD_EXECUTABLE) 

3. 以下为fb_test.c
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <linux/kd.h>

#include <stdio.h>

#define FBBIT_PER_PIXEL 32
#define FBBIT_PIXEL_IMAGE 16
#define PIXELS_WIDTH_BYTE 4
#define BYTE_PER_PIXEL 3
#define FB_GRAPHICS_PATH "/dev/graphics/fb0"
#define DEV_TTY0_PATH "/dev/tty0"

#define DISPLAY_ERROR -1
#define DISPLAY_SUCCESS 0

#define GET_BATTERYCAPACITY_ERR -1

#define MAX_STR 255

static struct {
    int fd;
    void *pixels;
    struct fb_fix_screeninfo fixed;
    struct fb_var_screeninfo var;
    int align_xres;
} fb;

int getBatteryCapacity(void)
{
    FILE *in;
    char tmpStr[MAX_STR + 1];
    char capfile[] = "/sys/class/power_supply/battery/capacity";

    if (capfile == NULL)
        return GET_BATTERYCAPACITY_ERR;

    in = fopen(capfile, "rt");
    if (in == NULL)
        return GET_BATTERYCAPACITY_ERR;

    if (fgets(tmpStr, MAX_STR, in) == NULL) {
        printf("Failed to read battery capacity!\n");
        fclose(in);
        return GET_BATTERYCAPACITY_ERR;

    }

    printf("Battery capacity(ascii): %s\n", tmpStr);
    fclose(in);

    return 0;//atoi(tmpStr);
}

static int vt_set_graphicsmode(int graphics)
{
    int fd, r;
    fd = open(DEV_TTY0_PATH, O_RDWR | O_SYNC);
    if (fd < 0)
        return DISPLAY_ERROR;
    r = ioctl(fd, KDSETMODE, graphics);
    close(fd);
    return r;
}

int display_init(void)
{
    fb.fd = open(FB_GRAPHICS_PATH, O_RDWR);
    if (fb.fd < 0)
        return DISPLAY_ERROR;

    if (ioctl(fb.fd, FBIOGET_FSCREENINFO, &fb.fixed) < 0)
        return DISPLAY_ERROR;
    if (ioctl(fb.fd, FBIOGET_VSCREENINFO, &fb.var) < 0)
        return DISPLAY_ERROR;
    fb.align_xres = fb.fixed.line_length /
        (fb.var.bits_per_pixel >> BYTE_PER_PIXEL);

    fb.pixels = mmap(0, fb.fixed.line_length * fb.var.yres_virtual,
        PROT_READ | PROT_WRITE, MAP_SHARED, fb.fd, 0);
    if (fb.pixels == MAP_FAILED)
        return DISPLAY_ERROR;

    vt_set_graphicsmode(KD_GRAPHICS);

    memset(fb.pixels, 0, fb.fixed.line_length * fb.var.yres_virtual);
    //display_update(fb.pixels, fb.align_xres, fb.var.yres);
    fb.var.activate = FB_ACTIVATE_FORCE;
    ioctl(fb.fd, FBIOPUT_VSCREENINFO, &fb.var);
    
    printf("display_init ok\n");

    return DISPLAY_SUCCESS;
}

void display_on(void)
{
    ioctl(fb.fd, FBIOBLANK, FB_BLANK_UNBLANK);
}

void display_off(void)
{
    ioctl(fb.fd, FBIOBLANK, FB_BLANK_POWERDOWN);
}

int main()
{    
    display_init();
    display_off();//关显示屏

    getBatteryCapacity();
    sleep(5);

    display_on();//开显示屏

    return 0;
}


### 使用 Android NDK 编译生成可执行文件 为了使用 Android NDK 编译生成可执行文件,需遵循特定配置流程。首先创建一个简单的 C 或 C++ 文件作为入口程序。 #### 创建源代码文件 假设有一个名为 `test.cpp` 的简单测试程序: ```cpp #include <stdio.h> int main(int argc, char **argv) { printf("This is my test\n"); return 0; } ``` 此段代码定义了一个基本的控制台应用程序[^3]。 #### 设置构建脚本 接着,在同一目录下编写 `Android.mk` 构建脚本来指定编译选项和目标模块名: ```makefile LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := test LOCAL_SRC_FILES := test.cpp include $(BUILD_EXECUTABLE) ``` 上述 Makefile 片段指定了要编译成独立二制形式而非共享库的目标模块名称及其对应的源文件列表。 #### 执行编译命令 完成以上准备工作之后,通过终端入项目根目录并调用 ndk-build 工具来启动实际编译过程: ```bash $ cd /path/to/project/ $ $ANDROID_NDK_HOME/ndk-build ``` 这会触发 NDK 自动读取本地存在的 `Android.mk` 并按照指示处理相关联的源文件集合[^1]。 #### 将生成的可执行文件部署至设备 一旦编译结束,会在项目的 obj/local/<abi>/ 和 libs/<abi>/ 路径下面找到新产生的 ELF 可执行映像文件。为了让它能在真实环境中运作起来,则需要借助 ADB 命令将其上传到已连接好的 Android 设备当中去: ```bash adb root adb remount adb push ./libs/arm64-v8a/test /system/bin/ adb shell chmod 755 /system/bin/test adb shell /system/bin/test ``` 这些指令序列确保了最终产物被放置在一个允许执行的位置,并赋予适当权限以便顺利加载与运行[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值