Cygwin环境使用第三方ARMGCC编译eCos系统
来源:互联网 发布:mac默认dock排列 编辑:程序博客网 时间:2024/06/06 08:47
第三方ARMGCC通常是基于Mingw32的,使用的是Windows路径,如C:\ecos\packages\infra\current\src\startup.cxx;而eCos配置工具生成的Makefile是基于Cygwin的,使用的是POSIX路径,如/cygdrive/c/packages/infra/current/src/startup.cxx。路径格式上的差别导致不能直接使用第三方ARMGCC编译eCos系统,而是需要一个中间程序来对路径进行转换。这里提供了执行路径转换的中间程序的源代码和编译使用说明。
eCos官网:http://ecos.sourceware.org
eCos中文技术网:http://www.52ecos.net
eCos交流QQ群:144940146。
http://blog.csdn.net/zoomdy/article/details/39553465
mingdu.zheng<at>gmail<dot>com
为什么需要第三方ARMGCC
eCos项目本身提供了GCC编译器,但是更新是比较慢的,在ARM公司已经推出Cortex-M7的年头还不支持Cortex-M4的FPU,毕竟eCos项目本身是做实时操作系统,编译器只是其配套工具之一。而第三方ARMGCC则几乎每个季度都会发布新版本以便支持最新的硬件。
第三方ARMGCC
这里推荐两款第三方ARMGCC
- GNU Tools for ARM Embedded Processors
https://launchpad.net/gcc-arm-embedded
看这个项目的简介,应该是ARM公司官方参与,可以自由下载,无需注册。
- Sourcery CodeBench Lite Edition
http://www.mentor.com/embedded-software/sourcery-tools/sourcery-codebench/editions/lite-edition/
这个原先是CodeSourcery公司的产品,现在被MentorGraphics收购了,其Lite版本可以免费下载使用,但是需要注册登记。
路径转换的实现
有两个地方需要进行路径转换,一是:传递给GCC的命令行参数,eCos配置工具生成的Makefile使用的是POSIX路径,而GCC需要的是Windows路径,因此首先需要将命令行参数中出现的POSIX路径转换成Windows路径再传递给GCC;二是:eCos编译系统需要使用GCC输出的依赖关系文件,第三方GCC生成的该文件使用的是Windows路径,而eCos编译系统需要的是POSIX路径,接下来就需要将依赖关系文件中的Windows路径转换成POSIX路径,源代码如下。
// main.cxx// by zoomdy (mingdu.zheng <at> gmail <dot> com)#ifdef __CYGWIN__#include <windows.h>#include <sys/cygwin.h>#include <sys/wait.h> // for waitpid#include <stdio.h>#include <stdlib.h>#include <string.h> // for strstr, strchr#include <unistd.h> // for execvp#include <stdbool.h>int main(int argc, char *argv[]){ // 首先处理程序名 char *p = strchr(argv[0], '-'); if(p == NULL) { fprintf(stderr, "invalid program name: %s", argv[0]); return EXIT_FAILURE; } p++; if(*p == '\0' || *p == '.') { fprintf(stderr, "invalid program name: %s", argv[0]); return EXIT_FAILURE; } char *q; for(q = argv[0]; *p != '\0'; q++, p++) { *q = *p; } *q = '\0'; // 处理其它参数 char buffer [MAX_PATH + 1]; char *deps = NULL; for(int i = 1; i < argc; i++) { p = strstr(argv[i], "/cygdrive/"); if(p != NULL) { cygwin_conv_to_win32_path(p, buffer); strcpy(p, buffer); } p = strstr(argv[i], "-Wp,-MD,"); if(p != NULL) { deps = p + strlen("-Wp,-MD,"); } // 如果发现所使用的参数名为null文件,那么创建一个空白文件 if(strcmp(argv[i], "/dev/null") == 0) { FILE* file = fopen("null", "w"); fclose(file); strcpy(argv[i], "null"); } } // 打印变更后的命令行 printf("==>"); for(int i = 0; i < argc; i++) { printf(argv[i]); printf(" "); } printf("\n"); // 调用变更后的命令行 if(deps == NULL) { // 如果不需要处理依赖关系文件,直接调用目标程序 int retval = execvp(argv[0], argv); if(retval == -1) { perror(argv[0]); return EXIT_FAILURE; } else { return EXIT_SUCCESS; } } else { // 如果需要处理依赖关系文件,那么创建子进程,并等子进程完成后处理依赖关系文件 pid_t pid = fork(); if(pid == -1) { perror(argv[0]); return EXIT_FAILURE; } else if(pid == 0) { int retval = execvp(argv[0], argv); if(retval == -1) { perror(argv[0]); return EXIT_FAILURE; } else { return EXIT_SUCCESS; } } else { int stat_val; waitpid(pid, &stat_val, 0); // 如果子进程正确完成,那么处理依赖关系文件 if(WIFEXITED(stat_val)) { if(WEXITSTATUS(stat_val) == EXIT_SUCCESS) { // 处理生成的依赖关系文件 char deps_cyg [MAX_PATH + 1]; strcpy(deps_cyg, deps); strcat(deps_cyg, ".cyg"); FILE* file_win = fopen(deps, "r"); FILE* file_cyg = fopen(deps_cyg, "w"); bool last_line = false; size_t len_line; for(int line = 0; last_line == false; line++) { p = fgets(buffer, sizeof(buffer), file_win); if(p == NULL) { perror(deps); return EXIT_FAILURE; } // 跳过前面的空格 for(size_t i = 0; i < sizeof(buffer); i++) { if(*p == ' ') { p++; } else { break; } } // 去掉尾部的回车换行符以及空格 len_line = strlen(p); for(size_t i = len_line - 1; i != 0; i--) { if(p[i] == ' ' || p[i] == '\r' || p[i] == '\n') { p[i] = '\0'; len_line--; } else { break; } } // 判断是否为最后一行 if(p[len_line - 1] == '\\') { last_line = false; p[len_line - 1] = '\0'; len_line--; } else { last_line = true; } // 去掉尾部的空格 for(size_t i = len_line - 1; i != 0; i--) { if(p[i] == ' ') { p[i] = '\0'; len_line--; } else { break; } } // 处理第一行的特殊情况,这种情况下,目标和依赖文件在同一行上 if(line == 0) { q = strstr(p, ".o:"); if(q != NULL) { p = q + strlen(".o:"); // 跳过前面的空格 for(size_t i = 0; i < sizeof(buffer); i++) { if(*p == ' ') { p++; } else { break; } } if(strlen(p) > 0) { cygwin_conv_to_posix_path(p, p); } } } // 从第二行开始,转换路径 if(line > 0) { // 将Windows路径转换成POSIX路径 cygwin_conv_to_posix_path(p, p); } // 如果不是最后一行,加入空格以及反斜杆 if(!last_line) { strcat(buffer, " \\\n"); } else { strcat(buffer, "\n"); } int retval = fputs(buffer, file_cyg); if(retval == EOF) { perror(deps_cyg); return EXIT_FAILURE; } } fclose(file_win); fclose(file_cyg); // 删除原文件,将处理后的文件重命名为原文件名 remove(deps); rename(deps_cyg, deps); return EXIT_SUCCESS; } // WEXITSTATUS(stat_val) } // WIFEXITED(stat_val) }// pid > 0 } // deps == NULL return EXIT_FAILURE;}#else#error "invoke native tool only use for cygwin environment"#endif
编译
把上面的源代码内容保存文件为mian.cxx,然后把下面的代码内容保存文件为Makefile,放在同一个目录下,然后打开Cygwin终端,进入存放上述两个文件的地方,敲入make。
# Makefileall: native.execp native.exe native-arm-none-eabi-gcc.execp native.exe native-arm-none-eabi-ar.execp native.exe native-arm-none-eabi-objcopy.exenative.exe: main.cxxgcc -Wall -O2 -o $@ $<clean:rm -rf *.exe
使用
把生成的native-arm-none-eabi-*.exe文件存储到你希望存储的目录,然后将该目录追加到系统的PATH环境变量中。接下来,在eCos配置工具中设置Global build options >> Global command prefix为native-arm-none-eabi。
将会发生什么
编译eCos系统时,凡是需要调用gcc的地方,都会首先调用native-arm-none-eabi-gcc,native-arm-none-eabi-gcc将命令行参数中的POSIX路径转换成Windows路径后调用arm-none-eabi-gcc,如果命令行中包含生成依赖关系文件的参数,那么native-arm-none-eabi-gcc将等待arm-none-eabi-gcc编译完成后处理依赖关系文件中的路径转换。
最佳解决方案
使用Linux系统,而不是Cygwin作为eCos开发环境。在Linux下开发eCos使用第三方ARMGCC就完全没有这个麻烦,因为大家使用的都是POSIX路径,没必要做任何转换,而且在Linux环境下的编译速度远快于Cygwin环境下的编译速度,毕竟Cygwin增加了系统调用的层次,而且Windows的文件访问缓存机制不如Linux,而且还有杀毒软件在中间掺和。当然,不是所有人都会用Linux,所有才有eCos的Cygwin版,有时间尝试一下Linux也是很好的,现如今的Linux桌面系统已经相当成熟。
- Cygwin环境使用第三方ARMGCC编译eCos系统
- 使用cygwin建立eCos开发环境(验证通过)
- 在Android源码环境下编译系统App使用第三方jar包的方法(备忘)
- cygwin下ecos开发环境的建立
- ecos开发环境建立 编译
- 编译第三方应用到系统中
- Android使用编译后的第三方库(集成环境下)
- Cygwin环境编译Snaphu
- Pycharm环境下使用第三方包
- 记录: android编译环境下加入第三方jar
- cygwin的安装使用以及交叉编译环境的搭建
- Ecplise编译Cygwin环境、使用CDT插件开发C/C++
- Ecplise使用CDT插件开发C/C++,编译环境Cygwin
- Ecplise编译Cygwin环境、使用CDT插件开发C/C++
- Cygwin环境下使用Android NDK r9c编译boost 1.55
- Eclipse环境下通过Cygwin使用NDK编译jni程序
- Cygwin环境下使用Android NDK r9c编译boost 1.55
- Ecplise编译Cygwin环境、使用CDT插件开发C/C++
- JS文件中加载jquery.js(JS文件添加其他JS文件)
- 城市轨道交通信号系统学习笔记1--ATC系统概述
- 基于范型的java验证框架
- 程序内存的分配
- https如何用java实现?
- Cygwin环境使用第三方ARMGCC编译eCos系统
- sql server - (存储过程、视图、函数、索引、锁、事务...)
- c语言 union 所占内存大小问题
- 在linux下配置nginx+java+php的环境
- 为什么会两次输出
- php+jQuery实现网络转盘抽奖
- 遍历安装某个路径下的所有apk文件
- c#数组的常见操作
- Android 高级绘图(实例-高级指南针表盘)