Merge: doc: fixed some typos and other misc. corrections
[nit.git] / src / platform / ios.nit
1 # This file is part of NIT ( http://www.nitlanguage.org )
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Compile programs for the iOS platform
16 module ios
17
18 import platform
19 import compiler::abstract_compiler
20 import xcode_templates
21 import app_annotations
22
23 redef class ToolContext
24 redef fun platform_from_name(name)
25 do
26 if name == "ios" then return new IOSPlatform
27 return super
28 end
29 end
30
31 private class IOSPlatform
32 super Platform
33
34 redef fun supports_libunwind do return false
35 redef fun supports_libgc do return true
36 redef fun toolchain(toolcontext, compiler) do return new IOSToolchain(toolcontext, compiler)
37 end
38
39 private class IosProject
40 super AppProject
41
42 redef fun namespace do return super.to_camel_case
43 end
44
45 private class IOSToolchain
46 super MakefileToolchain
47
48 # Root of the iOS project, usually `nit_compile/ios/`
49 var ios_project_root: String is noinit
50
51 # `app.nit` project for the current compilation target
52 var app_project = new IosProject(compiler.modelbuilder, compiler.mainmodule) is lazy
53
54 redef fun default_outname do return "{super}.app"
55
56 private var bdwgc_dir: nullable String = null
57
58 # Compile C files in `ios_project_root/app_project.name`
59 redef fun compile_dir
60 do
61 ios_project_root = root_compile_dir/"ios"
62 return ios_project_root/app_project.short_name
63 end
64
65 redef fun write_files(compile_dir, cfiles)
66 do
67 # Clear the project directory before writing anything
68 if ios_project_root.file_exists then ios_project_root.rmdir
69 compile_dir.mkdir
70
71 # Download the libgc/bdwgc sources
72 var nit_dir = toolcontext.nit_dir or else "."
73 var share_dir = (nit_dir/"share").realpath
74 if not share_dir.file_exists then
75 print "iOS project error: Nit share directory not found, please use the environment variable NIT_DIR"
76 exit 1
77 end
78
79 var bdwgc_dir = "{share_dir}/android-bdwgc/bdwgc"
80 self.bdwgc_dir = bdwgc_dir
81 if not bdwgc_dir.file_exists then
82 toolcontext.exec_and_check(["{share_dir}/android-bdwgc/setup.sh"], "iOS project error")
83 end
84
85 super
86 end
87
88 redef fun write_makefile(compile_dir, cfiles)
89 do
90 var project_name = app_project.short_name
91
92 # ---
93 # project_folder (source code)
94
95 # Create the plist in the same directory as the generated C code
96 if not compile_dir.file_exists then compile_dir.mkdir
97 var plist = new PlistTemplate(app_project.name, app_project.namespace,
98 app_project.version, app_project.version_code.to_s)
99 plist.write_to_file compile_dir/"Info.plist"
100
101 # Copy the folder `ios/AppIcon.appiconset` from the root of the project
102 var project_root = "."
103 var mpackage = compiler.mainmodule.first_real_mmodule.mpackage
104 if mpackage != null then
105 var root = mpackage.root
106 if root != null then
107 var filepath = root.filepath
108 if filepath != null then
109 project_root = filepath
110 end
111 end
112 end
113
114 # Copy all resources
115 var app_files = [project_root]
116 app_files.add_all app_project.files
117
118 var icons_found = false
119
120 # Prepare the `Assets.xcassets` folder
121 var target_assets_dir = compile_dir / "Assets.xcassets"
122 if not target_assets_dir.file_exists then target_assets_dir.mkdir
123 """
124 {
125 "info" : {
126 "version" : 1,
127 "author" : "nitc"
128 }
129 }""".write_to_file target_assets_dir / "Contents.json"
130
131 (compile_dir / "assets").mkdir
132
133 for path in app_files do
134
135 # Icon
136 var icon_dir = path / "ios" / "AppIcon.appiconset"
137 if icon_dir.file_exists then
138 icons_found = true
139
140
141 # copy the res folder to the compile dir
142 icon_dir = icon_dir.realpath
143 toolcontext.exec_and_check(["cp", "-R", icon_dir, target_assets_dir], "iOS project error")
144 end
145
146 # Assets
147 var assets_dir = path / "assets"
148 if assets_dir.file_exists then
149 assets_dir = assets_dir.realpath
150 toolcontext.exec_and_check(["cp", "-r", assets_dir, compile_dir], "iOS project error")
151 end
152 end
153
154 # ---
155 # project_folder.xcodeproj (projet meta data)
156
157 # Create an XCode project directory
158 var dir = ios_project_root/project_name+".xcodeproj"
159 if not dir.file_exists then dir.mkdir
160
161 # Create a PBX project file
162 var pbx = new PbxprojectTemplate(project_name)
163
164 ## Register all source files
165 for file in cfiles do pbx.add_file new PbxFile(file)
166 for file in compiler.extern_bodies do
167 pbx.add_file new PbxFile(file.filename.basename)
168 end
169
170 # GC
171 if compiler.target_platform.supports_libgc then
172 var bdwgc_dir = bdwgc_dir
173 assert bdwgc_dir != null
174
175 pbx.cflags = "-I '{bdwgc_dir}/include/' -I '{bdwgc_dir}/libatomic_ops/src' -fno-strict-aliasing " +
176 "-DWITH_LIBGC -DNO_EXECUTE_PERMISSION -DALL_INTERIOR_POINTERS -DGC_NO_THREADS_DISCOVERY -DNO_DYLD_BIND_FULLY_IMAGE " +
177 "-DGC_DISABLE_INCREMENTAL -DGC_THREADS -DUSE_MMAP -DUSE_MUNMAP -DGC_GCJ_SUPPORT -DJAVA_FINALIZATION "
178
179 var gc_file = new PbxFile("{bdwgc_dir}/extra/gc.c")
180 gc_file.cflags = "-Wno-tautological-pointer-compare"
181 pbx.add_file gc_file
182 end
183
184 # Basic storyboard, mainly to have the right screen size
185 var launch_screen_storyboard = new LaunchScreenStoryboardTemplate
186 launch_screen_storyboard.title = app_project.name
187 launch_screen_storyboard.subtitle = "app.nit"
188 launch_screen_storyboard.write_to_file ios_project_root / "LaunchScreen.storyboard"
189
190 # Register the Assets.xcassets folder in the project description
191 if icons_found then
192 var xcassets = new PbxFile("Assets.xcassets")
193 pbx.add_file xcassets
194 end
195
196 pbx.write_to_file dir / "project.pbxproj"
197 end
198
199 redef fun compile_c_code(compile_dir)
200 do
201 var project_name = app_project.short_name
202 var release = toolcontext.opt_release.value
203 var outfile = outfile(compiler.mainmodule)
204
205 # Compile with `xcodebuild`
206 #
207 # TODO support more than the iPhone and the simulator.
208 var compile_mode = if release then "Release" else "Debug"
209 var args = ["sh", "-c", "cd {ios_project_root}; " +
210 "xcodebuild -quiet -target '{project_name}' " +
211 "-destination 'platform=iOS Simulator,name=iPhone' " +
212 "-configuration {compile_mode} " +
213 "ONLY_ACTIVE_ARCH=NO "+
214 "-sdk iphonesimulator build"]
215 toolcontext.exec_and_check(args, "iOS project error")
216
217 # Move compiled app to destination
218 if outfile.file_exists then
219 var error = outfile.rmdir
220 if error != null then
221 print_error error
222 exit 1
223 end
224 end
225
226 args = ["mv", "{ios_project_root}/build/{compile_mode}-iphonesimulator/{project_name}.app", outfile]
227 toolcontext.exec_and_check(args, "iOS project error")
228 end
229 end