您的位置:首页 > 其它

CrossCompiler And Auto tools

2014-04-15 11:14 567 查看
什么是交叉编译?

在某个系统平台下可以产生另一个系统平台的可执行文件


•   
编译过程:

•   
 词法分析、语法分析、汇编器、连接器

•   
运行平台 vs 编译平台

•   
gcc –dumpmachine:

•   
 i486-linux-gnu:32bit  linux

•   
 i686-apple-darwin11:MacOS

•   
 arm-linux-androideabi:Android

•   
 arm-apple-darwin10: IOS

如何支持交叉编译?

支持交叉编译,首先要选择对的编译器,其次对编译过程引用的头文件、库要使用目标系统而不是运行系统的,最后还要明确支持系统机器类型

•   
编译器:

•   
 Android使用arm-linux-androideabi-gcc

•   
 IOS使用的是arm-apple-darwin10-llvm-gcc

•   
 选择目标系统路径

•   
 gcc –sysroot platforms/android-9/arch-arm

•   
 gcc –sysroot iPhoneOS.platform/Developer

•   
 选择目标系统机器(machine)类型

•   
 IOS和Android是arm的,但不同版本arm指令集不同,armv7s、armv5tej……

一个简单交叉编译的例子

•      
文件main.c:

•      
int main(int argc, char** argc) { printf(“ok\n”); }

•      
编译:

•      
gcc main.c –o test

•      
arm-apple-darwin10-llvm-gcc-4.2 main.c –o test.arm –sysroot=…/SDKs/iPhoneOS6.0.sdk –b armv7s

•      
file test: Mach-0 64-bit executable x86_64

•      
file test.arm: Mach-0 executable arm

编译器与目标系统相关选项

•      
--sysroot=${root}: 定义包含标准路径的prefix,如${root}/usr/include

•      
-b <machine>: 定义目标机器型号,一般编译器支持多种CPU及汇编,需要选择正确的型号,如arm5te、arm5tej、arm946e-s、armv7s等

 

交叉编译的困难是什么?

    本系统编译,所有路径都是以文件系统根路径为起点,在不同机器上是固定的,而交叉编译,编译器无法预知系统位置,编译器中在spec中预置的变量是不对的,需要逐一指定。


    本机编译,CPU等机器选项是可以测试得到,而交叉编译是无法指定,只能逐一指定。


•   
系统路径:

•   
 libgcc_s  crt1.o等gcc需要库路径

•   
 libc及其头文件的路径

•   
 目标系统路径,如IOS预置库及头文件路径

•   
 安装的模块路径,如依赖库及图文件路径

•   
 多机器选项:

•   
 支持ios5-7 simulator(i386),CPU选项不同

•   
  andriod指令集种类繁多的问题。

自己写Makefile的困难

如何检查编译器的能力,检查目标系统版本及能力、检查依赖模块及其版本,检查引用库支持所需功能情况,检查所需头文件情况……

•   
需要大量脚本:看看生成的configure有多大

•   
跨平台脚本能力,如BSD和Linux命令选项就有许多不同

•   
应对不同需求能力,不同目标系统需要不同,难以
4000
统一

 

解决可移植性及交叉编译方案

Automake工具

可移植性

检查系统

检查编译器

检查路径

生成Makefile

 

Auto-tools工具组

•   
Autoconf

– 
‘autoconf’:用configure.ac产生configure.

– 
‘autoheader’:用configure.ac产生config.h

– 
‘autoreconf’ :运行autoconf重新产生configure

– 
‘autoscan’: 扫描常见的移植问题.

– 
‘autoupdate’: 升级configure.ac中的废弃宏.

– 
‘ifnames’: 收集条件宏#if/#ifdef/.

– 
‘autom4te’:m4宏收集和实施,真正的code生成器

•   
Automake

– 
‘automake’:用configure.ac 和Makefile.am产生Makefile.in.

– 
‘aclocal’: 扫描configure.ac并将第三方宏定义放入aclocal.m4.

•   
Libtools

– 
‘libtoolize’:用于生产系统相关libtool

– 
‘libtool’:库管理命令行工具

Auto-tools 工作过程

 


 

如何编写configure.ac?

初始化

dnl Process this file with autoconf to produce a configure script.

define([svnversion], esyscmd([sh -c "LANG= LANGUAGE= svnversion|sed s/:/./g |tr -d '\n'"]))

dnl Initialization

AC_INIT([demo], [1.0.svnversion], [yantao.li@gnetis.com])

AC_CONFIG_AUX_DIR(auxdir)

AM_INIT_AUTOMAKE

AM_MAINTAINER_MODE

dnl Package information

AC_CONFIG_MACRO_DIR([m4])

编译器检查

dnl Checks for programs.

AC_PROG_CC

AC_PROG_CXX

AC_PROG_INSTALL

AC_PROG_LIBTOOL

AC_HEADER_STDC

库、函数、类型检查

dnl Checks for libraries.

dnl AC_CHECK_LIB([LIBRARY{> < = >= <= version}], [desc], [ACT-IF-FOUND], [ACT-IF-NOT])

dnl Check header

dnl AC_CHECK_HEADERS(HEADERS...)

dnl Checks for typedefs, structures, function and compiler characteristics.

dnl AC_CHECK_FUNCS([function], [if-found], [if-not-found])

dnl AC_CHECK_TYPES([struct aaa], [if-found], [if-not-found])

dnl Check related tools or programs.

dnl AC_CHECK_PROG(variable, program-name, value-if-found, [value-if-not-found], [path], [reject])

dnl tang check, keep it anyway, our prefix=/tang

构造命令行选项

dnl –enable-feature

dnl AC_ARG_ENABLE([feature], [help-text], [if-given], [if-not-given])

dnl –with-feature

dnl AC_ARG_WITH([package], [help-text], [if-given], [if-not-given])

dnl help string with format

dnl AS_HELP_STRING([--enable-feature],[describe])

定义autoheader和automake宏

dnl 定义automake宏,Makefile.am中以@macro@引用

macro=test

AC_SUBST([macro])

dnl 定义autoheader宏macro

AC_DEFINE([macro], [value], [macro description])

AC_DEFINE_UNQUOTED([macro],[value],[macro description])

dnl 对于automake条件

AM_CONDITIONAL([condition],[test sss])

自定义m4宏

dnl 定义宏AC_SET_DEFAULT_LOGLEVEL([level]), 缺省log level为level,可命令设定

AC_DEFUN([AC_SET_DEFAULT_LOGLEVEL], [

   if test -z "$1"; then LOG_LEVEL=7; else LOG_LEVEL=$1; fi

   AC_ARG_WITH([log],[AS_HELP_STRING([--with-log:],[

            set log level for debugging purpose, (default is set log level to $1)])], [

            echo "set log level to $enableval"

            AC_DEFINE_UNQUOTED([LOG_LEVEL], [$withval], [set the log level])],

[  echo "set log level to $LOG_LEVEL"

   AC_DEFINE_UNQUOTED(LOG_LEVEL, $LOG_LEVEL, [set the log level $LOG_LEVEL to disable log])

])   ])

定义输出文件

dnl Final Output

AC_OUTPUT([

    Makefile

    src/Makefile

    lib/Makefile 

    test/Makefile

    lib/test.pc

])

语法规则与Makefile相同

DATA:

    数据文档,一般无需编译,需要包含或安装的数据文件

HEADERS:

    头文件,包含需要安装或不需要安装的头文件

SCRIPTS:

    脚本,包含build需要的脚本或是需要安装的脚本

MANS:

    手册,是需要安装的程序说明书

TEXINFOS:

    提供info程序显示的手册,一般是程序说明书

PROGRAMS :

    要编译的可执行程序定义

LIBRARIES :

    要编译的库程序,一般是内部使用的静态库

LTLIBRARIES:

    需要libtool编译的程序库,一般是动态库程序,也支持静态库

实现可执行文件编译

# 定义可执行文件,安装到bindir下,命令参数--bindir=DIR,还有sbin_PROGRAMS,安装到sbindir

bin_PROGRAMS = test

#定义test的源文件,可以包含不安装的头文件

test_SOURCES = main.c

#定义连接test需要的库文件及附加的object文件,

test_LDADD = @FOO_OBJ@

# 定义编译test所依赖的目标

test_DEPENDENCIES = @FOO_OBJ@

# 定义附加的源文件

EXTRA_foo_SOURCES = foo.c

# 定义编译test说需要的编译选项, 对c编译器有效

test_CFLAGS=-Iaaa

# 定义编译test说需要的编译选项, 对c++编译器有效

test_CXXFLAGS=-O2

# 定义编译test说需要的编译选项, 对c和c++编译器都有效

test_CPPFLAGS=-O0

# 定义连接test说需要的选项

test_LDFLAGS=-lppp

 

实现静态库文件编译

# 定义可执行文件,安装到libdir下,命令参数--libdir=DIR

lib_LIBRARIES = libzlib.a

#定义zlib的源文件,可以包含不安装的头文件

libzlib_a_SOURCES = main.c

#定义连接需要的库文件及附加的object文件,LIBADD仅仅对LIBRARIES有效

libzlib_a_LIBADD = @FOO_OBJ@

# 定义编译zlib所依赖的目标

libzlib_a_DEPENDENCIES = @FOO_OBJ@

# 定义附加的源文件, 一般是生成源文件

EXTRA_libzlib_a_SOURCES = foo.c

# 定义编译zlib说需要的编译选项, 对c编译器有效

libzlib_a_CFLAGS=-Iaaa

# 定义连接zlib说需要的选项

libzlib_a_LDFLAGS=-lppp

实现动态库文件编译

# 定义可执行文件,安装到libdir下,命令参数--libdir=DIR

lib_LTLIBRARIES = libzlib.la

#定义zlib的源文件,可以包含不安装的头文件l

libzlib_la_SOURCES = main.c

#定义连接需要的库文件及附加的object文件

libzlib_la_LDADD = @FOO_OBJ@

# 定义编译zlib所依赖的目标

libzlib_la_DEPENDENCIES = @FOO_OBJ@

# 定义附加的源文件, 一般是生成源文件

EXTRA_libzlib_la_SOURCES = foo.c

# 定义编译zlib说需要的编译选项, 对c编译器有效

libzlib_la_CFLAGS=-Iaaa

# 定义连接zlib说需要的选项

libzlib_la_LDFLAGS=-lppp

库文件版本定义原则

…_LDFALGS = -version-info Current : Revision : Age

– 
初始值 0:0:0,除非确有代码修改,不要修改该值,且只在发布时修改

– 
如果有接口改变或增加,但二进制兼容,即原来程序可以不编译使用该库,改变原则是: current+1:0:age+1

– 
如果接口改变或删除接口,破坏了二进制兼容,原来程序需要修改编译才能使用该库,改变原则是:current+1:0:0

– 
如果接口没有变化,但内部有修改,改变原则是:current:revision+1:age

库输出版本:so. major. minor .build=(Current- Age).(Age).(Revision )

– 
兼容修改接口,major不变,minor增加,build归零

– 
不兼容修改,major增加,minor归零,build归零

– 
接口没有修改,但内部修改, major不变,minor不变,build增加

–  发布、安装相关问题


– 
发布dist包含以下文件

– 
所有SOURCES、HEADERS、TEXINFOS、 SCRIPTS、DATA、MANS定义文件,缺省进入dist包,除非是有nodist_前缀排除

– 
EXTRA_DIST 用于定义额外的发布文件列表

– 
对于其它如PROGRAMS,增加前缀dist_,可以用于增加到发布列表

– 
安装文件

– 
HEADERS、TEXINFOS、 SCRIPTS、DATA、MANS、 PROGRAMS、LTLIBRARIES和LIBRARIES都会进入安装,安装路径是以前缀定义,如bin_表名安装到bindir

– 
排除安装方式是noinst_前缀

Autoreconf

•      
autoreconf –fiv

        -v, --verbose

              verbosely report processing

       -f, --force

              consider all files obsolete

       -i, --install

              copy missing auxiliary files

       -m, --make

              when applicable, re-run ./configure && make

如何使用configure脚本?

使用环境变量

•      
支持一下环境变量替换:

•      
CC、CXX编译器设置

•      
CFLAGS、CPPFLAGS、CXXFLAGS初始化值替换

•      
LDFLAGS、LIBS初始化值替换

•      
使用环境变量:

•      
PATH

•      
PKG_CONFIG_PATH

•       常规命令行参数


•      
安装目录相关:

•      
--prefix:所有architecture无关文件安装路径

•      
--exec-prefix: architecture无关文件安装路径,缺省是prefix

•      
--bindir、--sbindir、--libexecdir定义相关安装路径

•      
交叉编译相关

•      
--build定义build运行的主机系统,缺省会自动判断

•      
--host定义编译目标运行的系统,以前使用—target,缺省使用编译器猜测

•      
使用依赖模块:

•      
--with-xxxx

•      
使用相关功能

•      
--enable-xxxx

•      
帮助

•      
--help

•       检查输出结果


•      
输出Makefile文件

•      
输出config.h文件

Automake产生Makefile有什么不同?

Make的目标

•      
all:build target

•      
check:build test program and running it

•      
Install:install target to ${DESTDIR}$bindir, …

•      
clean: clean all build result

•      
dist: distribute the source code

•      
distclean: clean make and configure script results

•      
make target DESTDIR=xxxx CFLAGS=xxxx

示例和问题

•      
对于交叉编译,特别是多目标交叉编译,autotools是如何支持,如何实现的呢?

 

支持不了多host?

使用多build路径支持多host

•      
 Makefile.am中可以使用@srcdir@和@builddir@来区分源文件路径和build中间文件路径

•      
 同一个srcdir可以支持多个builddir,各自完成自己的任务

•      
 Install是可以将不同builddir的路径安装到一个路径下,实现同一个包支持多个host

•      
 实例:

•      
 RabbitMQ client支持,iphone5、6、7及simulator

•      
 实现脚本一次构建完成

 

支持不了动态构建目标?

使用automake条件

•      
configure.ac定义条件CONDITION

•      
 AM_CONDITIONAL([CONDITION], [test x$p = xtrue])

•      
 Makefile.am使用条件:

•      
 if CONDITION

       tools=dbgtool

   else

  tools=

   bin_PROGRAMS=foo $(tools)

•      
 实例:

•      
 客户端测试程序,对不同目标有不同程序

•      
 对于Tang客户端,对OC和Java有不同分装代码需要编译

 

支持不了模块检查?

pkg-config

Autotools之外单独工具

定义m4宏:

    PKG_CHECK_MODULES([GLIB_THREADS], gthread-2.0 >= 2.2, have_glib_threads=yes, have_glib_threads=no)

Makefile.am中使用GLIB_THREAD_CFLAGS和GLIB_THREAD_LIBS宏引用module库和头文件,避免升级引起的麻烦

模块查找路径由PKG_CONFIG_PATH决定

模块描述文件是.pc(package configure)文件

注意.pc文件对交叉编译路径有所不同,内容中的包含路径要准确
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息