rta: add `live_types_to_csv` to provide human-readable info on types
[nit.git] / src / android_platform.nit
1 # This file is part of NIT ( http://www.nitlanguage.org )t
2 #
3 # Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Compile program for the Android platform
18 module android_platform
19
20 import platform
21 import abstract_compiler
22
23 redef class ToolContext
24 redef fun platform_from_name(name)
25 do
26 if name == "android" then return new AndroidPlatform
27 return super
28 end
29
30 fun exec_and_check(args: Array[String])
31 do
32 var prog = args.first
33 args.remove_at 0
34
35 # Is the wanted program available?
36 var proc_which = new IProcess.from_a("which", [prog])
37 proc_which.wait
38 var res = proc_which.status
39 if res != 0 then
40 print "Android project error: executable \"{prog}\" not found"
41 exit 1
42 end
43
44 # Execute the wanted program
45 var proc = new Process.from_a(prog, args)
46 proc.wait
47 res = proc.status
48 if res != 0 then
49 print "Android project error: execution of \"{prog} {args.join(" ")}\" failed"
50 exit 1
51 end
52 end
53 end
54
55 class AndroidPlatform
56 super Platform
57
58 redef fun toolchain(toolcontext) do return new AndroidToolchain(toolcontext)
59 end
60
61 class AndroidToolchain
62 super MakefileToolchain
63
64 var android_project_root: String
65
66 redef fun compile_dir
67 do
68 var normal_compile_dir = super
69 android_project_root = normal_compile_dir
70 return "{normal_compile_dir}/jni/nit_compile/"
71 end
72
73 redef fun write_files(compiler, compile_dir, cfiles)
74 do
75 var app_name = compiler.mainmodule.name
76 var app_package = "org.nitlanguage.{app_name}"
77 var app_version = "0.1"
78
79 var args = ["android", "-s", "create", "project", "--name", app_name,
80 "--target", "android-10", "--path", android_project_root,
81 "--package", app_package, "--activity", app_name]
82 toolcontext.exec_and_check(args)
83
84 # create compile_dir
85 var dir = "{android_project_root}/jni/"
86 if not dir.file_exists then dir.mkdir
87
88 dir = compile_dir
89 if not dir.file_exists then dir.mkdir
90
91 # compile normal C files
92 super(compiler, compile_dir, cfiles)
93
94 # Gather extra C files generated elsewhere than in super
95 for f in compiler.extern_bodies do
96 if f isa ExternCFile then cfiles.add(f.filename.basename(""))
97 end
98
99 ## Generate delagating makefile
100 dir = "{android_project_root}/jni/"
101 var file = new OFStream.open("{dir}/Android.mk")
102 file.write """
103 include $(call all-subdir-makefiles)
104 """
105 file.close
106
107 ### generate makefile into "{compile_dir}/Android.mk"
108 dir = compile_dir
109 file = new OFStream.open("{dir}/Android.mk")
110 file.write """
111 LOCAL_PATH := $(call my-dir)
112 include $(CLEAR_VARS)
113
114 LOCAL_CFLAGS := -D ANDROID
115 LOCAL_MODULE := main
116 LOCAL_SRC_FILES := \\
117 {{{cfiles.join(" \\\n")}}}
118 LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv1_CM -lz
119 LOCAL_STATIC_LIBRARIES := android_native_app_glue png
120
121 include $(BUILD_SHARED_LIBRARY)
122
123 $(call import-module,android/native_app_glue)
124 """
125 file.close
126
127 ### generate AndroidManifest.xml
128 dir = android_project_root
129 file = new OFStream.open("{dir}/AndroidManifest.xml")
130 file.write """<?xml version="1.0" encoding="utf-8"?>
131 <!-- BEGIN_INCLUDE(manifest) -->
132 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
133 package="{{{app_package}}}"
134 android:versionCode="1"
135 android:versionName="{{{app_version}}}"
136 android:debuggable="true">
137
138 <!-- This is the platform API where NativeActivity was introduced. -->
139 <uses-sdk android:minSdkVersion="9" />
140
141 <!-- This .apk has no Java code itself, so set hasCode to false. -->
142 <application android:label="@string/app_name" android:hasCode="false" android:debuggable="true">
143
144 <!-- Our activity is the built-in NativeActivity framework class.
145 This will take care of integrating with our NDK code. -->
146 <activity android:name="android.app.NativeActivity"
147 android:label="@string/app_name"
148 android:configChanges="orientation|keyboardHidden">
149 <!-- Tell NativeActivity the name of or .so -->
150 <meta-data android:name=\"{{{app_package}}}\"
151 android:value=\"{{{app_name}}}\" />
152 <intent-filter>
153 <action android:name="android.intent.action.MAIN" />
154 <category android:name="android.intent.category.LAUNCHER" />
155 </intent-filter>
156 </activity>
157 </application>
158
159 </manifest>
160 <!-- END_INCLUDE(manifest) -->
161 """
162 file.close
163
164 ### generate res/values/strings.xml
165 dir = "{android_project_root}/res/"
166 if not dir.file_exists then dir.mkdir
167 dir = "{dir}/values/"
168 if not dir.file_exists then dir.mkdir
169 file = new OFStream.open("{dir}/strings.xml")
170 file.write """<?xml version="1.0" encoding="utf-8"?>
171 <resources>
172 <string name="app_name">{{{app_name}}}</string>
173 </resources>"""
174 file.close
175
176 ### Link to png sources
177 # libpng is not available on Android NDK
178 # FIXME make obtionnal when we have alternatives to mnit
179 var nit_dir = "NIT_DIR".environ
180 var share_dir
181 if not nit_dir.is_empty then
182 share_dir = "{nit_dir}/share/"
183 else
184 share_dir = "{sys.program_name.dirname}/../share/"
185 end
186 if not share_dir.file_exists then
187 print "Android project error: Nit share directory not found, please use the environment variable NIT_DIR"
188 exit 1
189 end
190 share_dir = share_dir.realpath
191 var target_png_dir = "{android_project_root}/jni/png"
192 if not target_png_dir.file_exists then
193 toolcontext.exec_and_check(["ln", "-s", "{share_dir}/png/", target_png_dir])
194 end
195
196 ### Link to assets (for mnit and others)
197 # This will be accessed from `android_project_root`
198 var mainmodule_dir = compiler.mainmodule.location.file.filename.dirname
199 var assets_dir = "{mainmodule_dir}/../assets"
200 if not assets_dir.file_exists then assets_dir = "{mainmodule_dir}/assets"
201 if assets_dir.file_exists then
202 assets_dir = share_dir.realpath
203 var target_assets_dir = "{android_project_root}/assets"
204 if not target_assets_dir.file_exists then
205 toolcontext.exec_and_check(["ln", "-s", assets_dir, target_assets_dir])
206 end
207 end
208 end
209
210 redef fun write_makefile(compiler, compile_dir, cfiles)
211 do
212 # Do nothing, already done in `write_files`
213 end
214
215 redef fun compile_c_code(compiler, compile_dir)
216 do
217 # Compile C code (and thus Nit)
218 toolcontext.exec_and_check(["ndk-build", "-s", "-j", "4", "-C", android_project_root])
219
220 # Generate the apk
221 toolcontext.exec_and_check(["ant", "-q", "debug", "-f", android_project_root+"/build.xml"])
222
223 # Move the apk to the target
224 var outname = toolcontext.opt_output.value
225 if outname == null then outname = "{compiler.mainmodule.name}.apk"
226 toolcontext.exec_and_check(["mv", "{android_project_root}/bin/{compiler.mainmodule.name}-debug.apk", outname])
227 end
228 end