Apply PIE to nghttpx
[platform/upstream/nghttp2.git] / third-party / mruby / tasks / toolchains / android.rake
1 class MRuby::Toolchain::Android
2
3   DEFAULT_ARCH = 'armeabi' # TODO : Revise if arch should have a default
4
5   DEFAULT_TOOLCHAIN = :clang
6
7   DEFAULT_NDK_HOMES = %w{
8     /usr/local/opt/android-sdk/ndk-bundle
9     /usr/local/opt/android-ndk
10     ~/Android/Sdk/ndk-bundle
11     %LOCALAPPDATA%/Android/android-sdk/ndk-bundle
12     %LOCALAPPDATA%/Android/android-ndk
13     ~/Library/Android/sdk/ndk-bundle
14     ~/Library/Android/ndk
15   }
16
17   TOOLCHAINS = [:clang, :gcc]
18
19   ARCHITECTURES = %w{
20     armeabi armeabi-v7a arm64-v8a
21     x86 x86_64
22     mips mips64
23   }
24
25   class AndroidNDKHomeNotFound < StandardError
26     def message
27         <<-EOM
28 Couldn't find Android NDK Home.
29 Set ANDROID_NDK_HOME environment variable or set :ndk_home parameter
30         EOM
31     end
32   end
33
34   class PlatformDirNotFound < StandardError
35     def message
36         <<-EOM
37 Couldn't find Android NDK platform directories.
38 Set ANDROID_PLATFORM environment variable or set :platform parameter
39         EOM
40     end
41   end
42
43   attr_reader :params
44
45   def initialize(params)
46     @params = params
47   end
48
49   def bin_gcc(command)
50     command = command.to_s
51
52     command = case arch
53       when /armeabi/    then 'arm-linux-androideabi-'
54       when /arm64-v8a/  then 'aarch64-linux-android-'
55       when /x86_64/     then 'x86_64-linux-android-'
56       when /x86/        then 'i686-linux-android-'
57       when /mips64/     then 'mips64el-linux-android-'
58       when /mips/       then 'mipsel-linux-android-'
59       end + command
60
61     gcc_toolchain_path.join('bin', command).to_s
62   end
63
64   def bin(command)
65     command = command.to_s
66     toolchain_path.join('bin', command).to_s
67   end
68
69   def home_path
70     @home_path ||= Pathname(
71       params[:ndk_home] ||
72       ENV['ANDROID_NDK_HOME'] ||
73       DEFAULT_NDK_HOMES.find { |path|
74         path.gsub! '%LOCALAPPDATA%', ENV['LOCALAPPDATA'] || '%LOCALAPPDATA%'
75         path.gsub! '\\', '/'
76         path.gsub! '~', Dir.home || '~'
77         File.directory?(path)
78       } || raise(AndroidNDKHomeNotFound)
79     )
80   end
81
82   def toolchain
83     @toolchain ||= params.fetch(:toolchain){ DEFAULT_TOOLCHAIN }
84   end
85
86   def toolchain_path
87     @toolchain_path ||= case toolchain
88       when :gcc
89         gcc_toolchain_path
90       when :clang
91         home_path.join('toolchains', 'llvm' , 'prebuilt', host_platform)
92       end
93   end
94
95   def gcc_toolchain_path
96     if @gcc_toolchain_path === nil then
97       prefix = case arch
98         when /armeabi/    then 'arm-linux-androideabi-'
99         when /arm64-v8a/  then 'aarch64-linux-android-'
100         when /x86_64/     then 'x86_64-'
101         when /x86/        then 'x86-'
102         when /mips64/     then 'mips64el-linux-android-'
103         when /mips/       then 'mipsel-linux-android-'
104         end
105
106       test = case arch
107         when /armeabi/    then 'arm-linux-androideabi-*'
108         when /arm64-v8a/  then 'aarch64-linux-android-*'
109         when /x86_64/     then 'x86_64-*'
110         when /x86/        then 'x86-*'
111         when /mips64/     then 'mips64el-linux-android-*'
112         when /mips/       then 'mipsel-linux-android-*'
113         end
114
115       gcc_toolchain_version = Dir[home_path.join('toolchains', test)].map{|t| t.match(/-(\d+\.\d+)$/); $1.to_f }.max
116       @gcc_toolchain_path = home_path.join('toolchains', prefix + gcc_toolchain_version.to_s, 'prebuilt', host_platform)
117     end
118     @gcc_toolchain_path
119   end
120
121   def host_platform
122     @host_platform ||= case RUBY_PLATFORM
123       when /cygwin|mswin|mingw|bccwin|wince|emx/i
124         path = home_path.join('toolchains', 'llvm' , 'prebuilt', 'windows*')
125         Dir.glob(path.to_s){ |item|
126           next if File.file?(item)
127           path = Pathname(item)
128           break
129         }
130         path.basename
131       when /x86_64-darwin/i
132         'darwin-x86_64'
133       when /darwin/i
134         'darwin-x86'
135       when /x86_64-linux/i
136         'linux-x86_64'
137       when /linux/i
138         'linux-x86'
139       else
140         raise NotImplementedError, "Unknown host platform (#{RUBY_PLATFORM})"
141       end
142   end
143
144   def arch
145     @arch ||= (params[:arch] || ENV['ANDROID_ARCH'] || DEFAULT_ARCH).to_s
146   end
147
148   def sysroot
149     @sysroot ||= home_path.join('platforms', platform,
150         case arch
151         when /armeabi/    then 'arch-arm'
152         when /arm64-v8a/  then 'arch-arm64'
153         when /x86_64/     then 'arch-x86_64'
154         when /x86/        then 'arch-x86'
155         when /mips64/     then 'arch-mips64'
156         when /mips/       then 'arch-mips'
157         end
158       ).to_s
159   end
160
161   def platform
162     if @platform === nil then
163       @platform = params[:platform] || ENV['ANDROID_PLATFORM'] || nil
164       if @platform === nil
165         Dir.glob(home_path.join('platforms/android-*').to_s){ |item|
166           next if File.file?(item)
167           if @platform === nil
168             @platform = Integer(item.rpartition('-')[2])
169           else
170             platform = Integer(item.rpartition('-')[2])
171             @platform = platform > @platform ? platform : @platform
172           end
173         }
174         if @platform === nil
175           raise(PlatformDirNotFound)
176         else
177           @platform = "android-#{@platform}"
178         end
179       end
180     end
181     if Integer(@platform.rpartition('-')[2]) < 21
182       case arch
183       when /arm64-v8a/, /x86_64/, /mips64/
184         raise NotImplementedError, "Platform (#{@platform}) has no implementation for architecture (#{arch})"
185       end
186     end
187     @platform
188   end
189
190   def armeabi_v7a_mfpu
191     @armeabi_v7a_mfpu ||= (params[:mfpu] || 'vfpv3-d16').to_s
192   end
193
194   def armeabi_v7a_mfloat_abi
195     @armeabi_v7a_mfloat_abi ||= (params[:mfloat_abi] || 'softfp').to_s
196   end
197
198   def no_warn_mismatch
199     if %W(soft softfp).include? armeabi_v7a_mfloat_abi
200       ''
201     else
202       ',--no-warn-mismatch'
203     end
204   end
205
206   def cc
207     case toolchain
208     when :gcc then bin_gcc('gcc')
209     when :clang then bin('clang')
210     end
211   end
212
213   def ar
214     case toolchain
215     when :gcc   then bin_gcc('ar')
216     when :clang then bin_gcc('ar')
217     end
218   end
219
220   def ctarget
221     flags = []
222
223     case toolchain
224     when :gcc
225       case arch
226       when /armeabi-v7a/  then flags += %W(-march=armv7-a)
227       when /armeabi/      then flags += %W(-march=armv5te)
228       when /arm64-v8a/    then flags += %W(-march=armv8-a)
229       when /x86_64/       then flags += %W(-march=x86-64)
230       when /x86/          then flags += %W(-march=i686)
231       when /mips64/       then flags += %W(-march=mips64r6)
232       when /mips/         then flags += %W(-march=mips32)
233       end
234     when :clang
235       case arch
236       when /armeabi-v7a/  then flags += %W(-target armv7-none-linux-androideabi)
237       when /armeabi/      then flags += %W(-target armv5te-none-linux-androideabi)
238       when /arm64-v8a/    then flags += %W(-target aarch64-none-linux-android)
239       when /x86_64/       then flags += %W(-target x86_64-none-linux-android)
240       when /x86/          then flags += %W(-target i686-none-linux-android)
241       when /mips64/       then flags += %W(-target mips64el-none-linux-android)
242       when /mips/         then flags += %W(-target mipsel-none-linux-android)
243       end
244     end
245
246     case arch
247     when /armeabi-v7a/  then flags += %W(-mfpu=#{armeabi_v7a_mfpu} -mfloat-abi=#{armeabi_v7a_mfloat_abi})
248     when /armeabi/      then flags += %W(-mtune=xscale -msoft-float)
249     when /arm64-v8a/    then flags += %W()
250     when /x86_64/       then flags += %W()
251     when /x86/          then flags += %W()
252     when /mips64/       then flags += %W(-fmessage-length=0)
253     when /mips/         then flags += %W(-fmessage-length=0)
254     end
255
256     flags
257   end
258
259   def cflags
260     flags = []
261
262     flags += %W(-MMD -MP -D__android__ -DANDROID --sysroot="#{sysroot}")
263     flags += ctarget
264     case toolchain
265     when :gcc
266     when :clang
267       flags += %W(-gcc-toolchain "#{gcc_toolchain_path}" -Wno-invalid-command-line-argument -Wno-unused-command-line-argument)
268     end
269     flags += %W(-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes)
270
271     flags
272   end
273
274   def ldflags
275     flags = []
276
277     flags += %W(--sysroot="#{sysroot}")
278
279     flags
280   end
281
282   def ldflags_before_libraries
283     flags = []
284
285     case toolchain
286     when :gcc
287       case arch
288       when /armeabi-v7a/  then flags += %W(-Wl#{no_warn_mismatch})
289       end
290     when :clang
291       flags += %W(-gcc-toolchain "#{gcc_toolchain_path.to_s}")
292       case arch
293       when /armeabi-v7a/  then flags += %W(-target armv7-none-linux-androideabi -Wl,--fix-cortex-a8#{no_warn_mismatch})
294       when /armeabi/      then flags += %W(-target armv5te-none-linux-androideabi)
295       when /arm64-v8a/    then flags += %W(-target aarch64-none-linux-android)
296       when /x86_64/       then flags += %W(-target x86_64-none-linux-android)
297       when /x86/          then flags += %W(-target i686-none-linux-android)
298       when /mips64/       then flags += %W(-target mips64el-none-linux-android)
299       when /mips/         then flags += %W(-target mipsel-none-linux-android)
300       end
301     end
302     flags += %W(-no-canonical-prefixes)
303
304     flags
305   end
306 end
307
308 MRuby::Toolchain.new(:android) do |conf, params|
309   android = MRuby::Toolchain::Android.new(params)
310
311   toolchain android.toolchain
312
313   [conf.cc, conf.cxx, conf.objc, conf.asm].each do |cc|
314     cc.command = android.cc
315     cc.flags = android.cflags
316   end
317
318   conf.archiver.command = android.ar
319   conf.linker.command = android.cc
320   conf.linker.flags = android.ldflags
321   conf.linker.flags_before_libraries = android.ldflags_before_libraries
322 end