The Build System


Android Build system은 그 어떤 전통적인 Build System과도 닮아 있지 않다.

이렇게 거대한 Open source Project는 존재하지 않았기 때문이다.


make는 사용하지 않는다.

Linux kernel 컴파일시 항상 보았던, menu-config도 없다. 

따라서 이해를 위해서 기존의 임베디드 개발에 익숙한 사람들도 시간을 좀 들여야 한다.



Android Build System은 Android.mk 파일에 의해서 어떻게 동작할지가 기술 된다.

이것들의 갯수는 아래와 같다.


2.3.7 Gingerbread, 1,143

4.2 Jelly Bean 2,037

5.1.0_r3 Lollipop 3849




기존 커널 빌딩은

정적이지만, 안드로이드는 동적이다. envsetup.sh 와 lunch를 통해서 동적으로 사용자와 반응 하게된다.

그리고 조정가능한 요소들이 매우 제한적이다.



Build system은 Objet 파일을 만들어 내지 않는다.

중간 결과 따위가 없다.

대신 out/ 디렉터리에 중간 결과물들이 있다. 이것은 .o 파일 따위가 아니다.


마지막으로 아주 심하게 GNU-make 기능에 의존적이다. 다시말하면 정확히 3.81 version에 의존적이다.

3.82는 패치 없이는 동작하지 않는다.

즉, define, include, ifndef 같은 것들이다.


왜 구글이 Recursive Make를 안쓰는지는

"Recursive Make Considered Harmful", Peter Miller를 확인하자.

여기서 single global makefile 이 왜 좋은지를 알 수 있다.

구글은 module-provided .mk file을 가지고 단일 makefile로 컴파일을 한다.



Architecture



<그림 안드로이드 빌드 시스템의 구조>


build/core 디렉터리에서 main.mk를 찾을 수 있다.

각각의 mk 파일들이 모여서 엄청나게 거대한 단일 makefile로 만들어 지며, 이것은 각각의 작은 프로젝트들을 모두 컴파일 한다.

다시한번 말하지만 여러개의 makefile이 재귀적으로 호출되는 구조가 아니다.


Android system을 make해보면

어느정도 긴시간을 아무것도 출력하지 않는것을 알 수 있다.

도대체 그 시간에 무엇을 하고 있는 것일까?

그 시간에 Android.mk들이 서로 조합되는 시간일 것이다. 이것을 실제로 보고 싶은 경우

build/core/main.mk를 수정 하면 된다.






Configuration



빌드를 configure하는 방법은

envsetup.sh 과 lunch cmmand를 이요하는 것이다.


buildspec.mk 파일은 가능한 요건들을 출력 한다.



TARGET_PRODUCT

generic: 기본적인 것

full: 대부분의 앱들이 가능한 버전이다.

full_crespo: full과 같지만, crespo (nexus S)를 위한것

full_grouper: full과 같지만, grouper (nexus 7)을 위한것

sim: simulator를 위한것 하지만 2.3 (gingerbread)에서만 가능 했다.

sdk: 


TARGET_BUILD_VARIANT

eng: user, debug, eng를 포함한다.

userdebug: user, debug를 포함한다.

user: user를 포함한다.


TARGET_BUILD_TYPE

release 아니면 debug 


TARGET_TOOLS_PREFIX

기본적으로 prebuild에 있는 cross development toolchain을 사용 한다.

다른 toolchain을 사용하고 싶으면 새로 설정하면 된다.


OUT_DIR

모든 결과물을 out 디렉터리에 넣는다.

다른 디렉터리를 설정하면 다르게 할 수 있다.


BUILD_ENV_SEQUENCE_NUMBER



Output



host와 target을 위해서 각각 컴파일을 진행 









'Computer Science > Embedded Android' 카테고리의 다른 글

3. AOSP Jump-Start  (0) 2013.05.07

AOSP Jump Start


1단계: repo를 설치한다.

repo라는 것은 싱글 쉘 스크립트로 개발되어져 있다.

이것의 주된 기능은 git repositories에 대해서  pull과 push를 작업하기 위해 작성된 스크립트 프로그램이다.


repo를 할때 특별한 branch를 설정하면 그것을 다운 받게된다.

하지만 특별한  branch를 주지 않는다면, master branch를 다운 받게 된다.


그리고 가급적이면 이러한 master branch를 받는것이 현명하다. 왜냐하면 주석이나 각종 tip들이 많이 포함되어저 있기 때문이다.


repo의 사용법은 아래와 같이 입력 하면된다.


root@ubuntu:~/Android_Platform/cm7/out# repo help
usage: repo COMMAND [ARGS]

The most commonly used repo commands are:

  abandon      Permanently abandon a development branch
  branch       View current topic branches
  branches     View current topic branches
  checkout     Checkout a branch for development
  cherry-pick  Cherry-pick a change.
  diff         Show changes between commit and working tree
  download     Download and checkout a change
  grep         Print lines matching a pattern
  init         Initialize repo in the current directory
  list         List projects and their associated directories
  overview     Display overview of unmerged project branches
  prune        Prune (delete) already merged topics
  rebase       Rebase local branches on upstream branch
  smartsync    Update working tree to the latest known good revision
  stage        Stage file(s) for commit
  start        Start a new branch for development
  status       Show the working tree status
  sync         Update working tree to the latest revision
  upload       Upload changes for code review

See 'repo help <command>' for more information on a specific command.
See 'repo help --all' for a complete list of recognized commands.


root@ubuntu:~/Android_Platform/cm7/out# repo help diff

Summary
-------
Show changes between commit and working tree

Usage: repo diff [<project>...]

The -u option causes 'repo diff' to generate diff output with file paths
relative to the repository root, so the output can be applied
to the Unix 'patch' command.

Options:
  -h, --help      show this help message and exit
  -u, --absolute  Paths are relative to the repository root




Inside the AOSP


아래의 표는 AOSP의 최상위 레벨의 디렉터리들을 나타낸 것이다. 그것의 내용은 2.3.7과 4.2 버전을 나누어서 요약해서 보여주고 있다. 포함하지 않는것은 N/A로 표현 되어있다. 또한 각각의 사이즈들은 .git 디렉터리는 포함하지 않은 것이다. 




주석 a: 아마도 미래에 쓰일 실험 적인 코드들을 저장하고 있는것 같다. 이것은 git log를 분석한 결과로써 추측이다.


딱 보면 알다시피 prebuilt 또는 prebuilts와 external이 전체중 각각 75%, 65%에 달한다. 젤리빈과 진저브레드에 대해서


이 두 디렉터리는 GNU toolchain versions, kernel images, common libraries and frameworks(OpenSSL and WebKit 등)을 포함하고 있다. 또한 자신들이 만든 내용들도 포함하고 있다.

하지만 이러한 정보는 얼마나 Android가 만은 open source project들에 의존하고 있는지를 알 수 있다.

이것의 양은 대략적으로 진저브레드의 경우 800MB이며 젤리빈의 경우 2GB 이다. 


아래의 그림 3-2는 안드로이드의 소스코드들이 각각 어디에 위치하고 있는지를 나태내고 있다. 


하지만, 중요한것은 framework/base 안에 거의 다 있다.

또한 system/core에도 중요한 내용들이 많이 있다. 

이것은 아래의 Table 3-2와 table 3-3으로 나타내어진다. 임베디드 개발자라면, 이것에 관심을 같고 수정을 해야할 것이다.









개요


Android는 리눅스 커널과 다르게 makefile에 의존하지 않는다.

그대신 android.mk 파일에 의존한다. 이것은 빌드를 위한 module이다.


Android build "modules" have nothing to do with kernel "modules."

Within the context of Android's build system, a "moudle" is any component of the AOSP that needs to be built. The might be a binary, an app package, a library, etc., and it might have to be built for the target or the host, but it's still a "module" with regards to the build system.



Android에서의 빌드 환경 설정 방법

리눅스 커널과 다르게 menuconfig와 autotools를 사용하지 않는다.




□ Building the SDK for Linux and Mac OS


자신만의 SDK를 만들어서 배포하고 싶으면 AOSP을 이용하면 된다.


. build/envsetup.sh

lunch sdk-eng

make sdk


이렇게 하면 AOSP 디렉터리 안에 out/host/linux-x86/sdk에 보면 ZIP 파일이 있을 것이다.

이것을 이제 이용하면 된다.


그 밖에도 아래의 위치에가면 많은 *. jar 파일들이 존재한다.


/aosp-4.2_r2/out/host/linux-x86/framework




□ Running Android


컴파일 성공하면 커스텀 빌트 이미지를 실행 할 수 있다.


$ emulator &


이렇게 하면 컴파일되어진 커스텀 에뮬레이터가 실행되어 진다. 

에뮬레이터의 경우 처음 부팅할때, 달빅은 JIT cache를 앱 실행을 위해서 생성하게 된다. 주목할 것은, 이러한 Dalvic cache는 에뮬레이터마다 유니크 하지 않다는 것이다. 이러한 자세한 내용은 7장에서 다루도록 하겠다.



하지만 shell이 닫혔다면, 다음과 같이 환경 스크립트를 다시 실행 해줘야 한다.

$ . build/envsetup.sh

$ lunch


이외에도 거의 대부분의 too들이 AOSP에는 들어 있기 때문에, 저 커멘드를 실행해 주면 adb와 같은 것들을 모두 실행 할 수 있다.



□ Using the Android Debug Bridge (ADB)


Android에 있는 ADB의 경우 일단 host에서 데몬이 돌아가고 그것과 host client 프로그램이 통신하는 형태이다.

host의 데몬서버는 target device의 데몬과 통신하면서 작업을 요청하게 된다.


자세한 명령어 사용 법은 google 홈페이지의 developer guide 를 참고한다.

소스코드 분석은 6장에서 다루도록 한다.


□ Mastering the Emulator


에뮬레이터는 최근 arm과 x86 타겟으로 출시 되어 있는 상태이다. 상당히 제한적이다고 할 수 있다. 

에뮬레이터는 android의 많은 부분적 이슈들중에서 상당히 복잡한 이슈에 해당한다. 이것을 깊이 있게 파는것은

안드로이드 이해의 범위를 넘어선 일이다.

따라서 에뮬레이터의 핵심 특징들만 간단히 조사하고 가는 수준에서 마무리 하겠다. 자세한것을 보고싶으면 qemu와 에뮬레이션 기법들을 공부해야 할 것이다.


emulator는 여러 플래그를 덪 붙여서 실행 할 수 있다. 플레그들은 아래와 같다.




이중에서 재미 있는 옵션은 -kernel이다. 이것은 emulator가 다른 ㅋ널을 사용할 수 있도록 한다. 에뮬레이터는 기본적으로, prebuilt/android-arm/kernel/ 에 들어있는 커널을 사용하게 된다. 


만약 너가 모듈을 지원하는 kernel을 사용하기를 원한다면, 그렇게 빌드한다음 아래의 명령어로 새롭게 적제해서 사용할 수 있다. 왜냐하면, prebuilt에 있는 kernel은 module을 지원하고 있지 않기 대문이다. 


$ emulator -kernel path_to_your_kernel_image/zImage 


또한 에뮬레이터에서 커널의 boot message를 확인 할 수도 있다. 



이 밖에도, 결국 emulator는 안드로이드 개발자가 QEMU에 wrapper를 한 형태이기 때문에 qemu의 많은 명령어들을 그대로 사용할 수도 있다.


$ emulaotr -qemu -h


또한 에뮬레이터는 telnet으로도 접속이 가능하다.


telent localhost 5554


그리고 텔넷 상태에서 포트포워딩을 사용해서 호스트의 포트를 타겟으로 redirection 할수도 있다.


redir add tcp:8080:80


이렇게하면 host에서 8080으로 접속된 어떤 프로그램이 명령하는 것들은 80번 포트를 통해서 에뮬레이트된 안드로이드로 리스닝 되어진다. 디펄트 안드로이드는 물론 80번 포트에서 아무것도 리슨 하지 않는다.

하지만 예를들면, 당신이 android에서 BusyBox's httpd를 실행 했다면, 이 방법을 이용해서 그것과 연결 되어 질 수 있다.


또 재미 있는 것은 당신의 호스트에서 아파치가 실행 중이라면, 에뮬레이터가 가지는 브라우저에 에뮬레이터 주소를 입력하면 해당 하파치가서비스하고 있는 컨텐트를 볼 수도 있다.


더 자세한 정보는 Google Developers Guide를 참고 한다.






'Computer Science > Embedded Android' 카테고리의 다른 글

4. The Build System  (0) 2015.04.25

+ Recent posts