tests: test_syntax now reports other errors before the pkgconfig error
[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 false
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 # Compile C files in `ios_project_root/app_project.name`
57 redef fun compile_dir
58 do
59 ios_project_root = root_compile_dir/"ios"
60 return ios_project_root/app_project.short_name
61 end
62
63 redef fun write_files(compile_dir, cfiles)
64 do
65 # Clear the project directory before writing anything
66 if ios_project_root.file_exists then ios_project_root.rmdir
67 compile_dir.mkdir
68
69 super
70 end
71
72 redef fun write_makefile(compile_dir, cfiles)
73 do
74 var project_name = app_project.short_name
75
76 # ---
77 # project_folder (source code)
78
79 # Create the plist in the same directory as the generated C code
80 if not compile_dir.file_exists then compile_dir.mkdir
81 var plist = new PlistTemplate(app_project.name, app_project.namespace,
82 app_project.version, app_project.version_code.to_s)
83 plist.write_to_file compile_dir/"Info.plist"
84
85 # Copy the folder `ios/AppIcon.appiconset` from the root of the project
86 var project_root = "."
87 var mpackage = compiler.mainmodule.first_real_mmodule.mpackage
88 if mpackage != null then
89 var root = mpackage.root
90 if root != null then
91 var filepath = root.filepath
92 if filepath != null then
93 project_root = filepath
94 end
95 end
96 end
97
98 # Copy all resources
99 var app_files = [project_root]
100 app_files.add_all app_project.files
101
102 var icons_found = false
103
104 for path in app_files do
105 var icon_dir = path / "ios" / "AppIcon.appiconset"
106 if icon_dir.file_exists then
107 icons_found = true
108
109 # Prepare the `Assets.xcassets` folder
110 var target_assets_dir = compile_dir / "Assets.xcassets"
111 if not target_assets_dir.file_exists then target_assets_dir.mkdir
112
113 """
114 {
115 "info" : {
116 "version" : 1,
117 "author" : "nitc"
118 }
119 }""".write_to_file target_assets_dir / "Contents.json"
120
121 # copy the res folder to the compile dir
122 icon_dir = icon_dir.realpath
123 toolcontext.exec_and_check(["cp", "-R", icon_dir, target_assets_dir], "iOS project error")
124 end
125 end
126
127 # TODO Register asset files
128
129 # ---
130 # project_folder.xcodeproj (projet meta data)
131
132 # Create an XCode project directory
133 var dir = ios_project_root/project_name+".xcodeproj"
134 if not dir.file_exists then dir.mkdir
135
136 # Create a PBX project file
137 var pbx = new PbxprojectTemplate(project_name)
138
139 ## Register all source files
140 for file in cfiles do pbx.add_file new PbxFile(file)
141 for file in compiler.extern_bodies do
142 pbx.add_file new PbxFile(file.filename.basename)
143 end
144
145 # Basic storyboard, mainly to have the right screen size
146 var launch_screen_storyboard = new LaunchScreenStoryboardTemplate
147 launch_screen_storyboard.title = app_project.name
148 launch_screen_storyboard.subtitle = "app.nit"
149 launch_screen_storyboard.write_to_file ios_project_root / "LaunchScreen.storyboard"
150
151 # Register the Assets.xcassets folder in the project description
152 if icons_found then
153 var xcassets = new PbxFile("Assets.xcassets")
154 pbx.add_file xcassets
155 end
156
157 pbx.write_to_file dir / "project.pbxproj"
158 end
159
160 redef fun compile_c_code(compile_dir)
161 do
162 var project_name = app_project.short_name
163 var release = toolcontext.opt_release.value
164 var outfile = outfile(compiler.mainmodule)
165
166 # Compile with `xcodebuild`
167 #
168 # TODO support more than the iPhone and the simulator.
169 var compile_mode = if release then "Release" else "Debug"
170 var args = ["sh", "-c", "cd {ios_project_root}; " +
171 "xcodebuild -quiet -target '{project_name}' " +
172 "-destination 'platform=iOS Simulator,name=iPhone' " +
173 "-configuration {compile_mode} " +
174 "ONLY_ACTIVE_ARCH=NO "+
175 "-sdk iphonesimulator build"]
176 toolcontext.exec_and_check(args, "iOS project error")
177
178 # Move compiled app to destination
179 if outfile.file_exists then
180 var error = outfile.rmdir
181 if error != null then
182 print_error error
183 exit 1
184 end
185 end
186
187 args = ["mv", "{ios_project_root}/build/{compile_mode}-iphonesimulator/{project_name}.app", outfile]
188 toolcontext.exec_and_check(args, "iOS project error")
189 end
190 end