1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
17 # FFI support for Objective-C
19 # Compiles all Objective-C code with clang. The user module must define
22 # This module is heavily based on the C++ FFI.
28 redef class FFILanguageAssignationPhase
29 # The Objective-C language visitor
30 var objc_language
: FFILanguage = new ObjCLanguage(self)
34 private var objc_file
: nullable ObjCCompilationUnit = null
37 # The Objective-C langugage visitor
41 redef fun identify_language
(n
) do return n
.is_objc
43 redef fun compile_module_block
(block
, ecc
, mmodule
)
45 if mmodule
.objc_file
== null then mmodule
.objc_file
= new ObjCCompilationUnit
47 if block
.is_objc_header
then
48 mmodule
.objc_file
.header_custom
.add block
.location
.as_line_pragma
49 mmodule
.objc_file
.header_custom
.add block
.code
50 else if block
.is_objc_body
then
51 mmodule
.objc_file
.body_custom
.add block
.location
.as_line_pragma
52 mmodule
.objc_file
.body_custom
.add block
.code
56 redef fun compile_extern_method
(block
, m
, ecc
, mmodule
)
58 if mmodule
.objc_file
== null then mmodule
.objc_file
= new ObjCCompilationUnit
60 var mpropdef
= m
.mpropdef
61 var recv_mtype
= mpropdef
.mclassdef
.bound_mtype
62 var csignature
= mpropdef
.mproperty
.build_csignature
(
63 recv_mtype
, mmodule
, "___impl", long_signature
, from_objc_call_context
)
65 var fc
= new CFunction(csignature
)
66 fc
.decls
.add block
.location
.as_line_pragma
67 fc
.exprs
.add block
.code
68 mmodule
.objc_file
.add_exported_function fc
71 redef fun compile_extern_class
(block
, m
, ecc
, mmodule
) do end
73 redef fun get_ftype
(block
, m
) do return new ForeignObjCType(block
.code
)
75 redef fun compile_to_files
(mmodule
, compdir
)
77 var objc_file
= mmodule
.objc_file
78 assert objc_file
!= null
80 # write .m and _m.h file
81 mmodule
.objc_file
.header_c_types
.add
"""
82 #include "{{{mmodule.cname}}}._ffi.h"
85 var file
= objc_file
.write_to_files
(mmodule
, compdir
)
87 # add compilation to makefile
88 mmodule
.ffi_files
.add file
91 redef fun compile_callback
(callback
, mmodule
, mainmodule
, ecc
)
93 callback
.compile_callback_to_objc
(mmodule
, mainmodule
)
97 redef class AExternCodeBlock
98 # Is this Objective-C code?
99 fun is_objc
: Bool do return language_name
!= null and
100 (language_name_lowered
== "objc" or language_name_lowered
.has_prefix
("objc "))
102 # Is this Objective-C code for the body file?
103 fun is_objc_body
: Bool do return language_name
!= null and
104 (language_name_lowered
== "objc" or language_name_lowered
== "objc body")
106 # Is this Objective-C code for the header file?
107 fun is_objc_header
: Bool do return language_name
!= null and
108 (language_name_lowered
== "objc header")
111 private class ObjCCompilationUnit
112 super CCompilationUnit
114 # Write this compilation unit to Objective-C source files
115 fun write_to_files
(mmodule
: MModule, compdir
: String): ExternObjCFile
117 var base_name
= "{mmodule.cname}._ffi"
119 var h_file
= "{base_name}_m.h"
120 var guard
= "{mmodule.cname.to_s.to_upper}_NIT_OBJC_H"
121 write_header_to_file
(mmodule
, compdir
/h_file
, new Array[String], guard
)
123 var c_file
= "{base_name}.m"
124 write_body_to_file
(mmodule
, compdir
/c_file
, ["\"{h_file}\
""])
126 files
.add compdir
/c_file
128 mmodule
.c_linker_options
= "{mmodule.c_linker_options} -lobjc"
130 return new ExternObjCFile(compdir
/c_file
, mmodule
)
138 # Associated `MModule`
141 redef fun makefile_rule_name
do return "{filename.basename(".m")}_m.o"
142 redef fun makefile_rule_content
do
143 return "clang $(CFLAGS) -c {filename.basename("")} -o {makefile_rule_name}"
145 redef fun compiles_to_o_file
do return true
148 # An Objective-C type
149 class ForeignObjCType
153 var objc_type
: String
156 redef class NitniCallback
157 # Compile this callback to be callable from Objective-C
158 fun compile_callback_to_objc
(mmodule
: MModule, mainmodule
: MModule) do end
161 redef class MExplicitCall
162 redef fun compile_callback_to_objc
(mmodule
, mainmodule
)
164 var mproperty
= mproperty
165 assert mproperty
isa MMethod
167 var objc_signature
= mproperty
.build_csignature
(recv_mtype
, mainmodule
, null, short_signature
, from_objc_call_context
)
168 var ccall
= mproperty
.build_ccall
(recv_mtype
, mainmodule
, null, long_signature
, from_objc_call_context
, null)
169 var fc
= new CFunction(objc_signature
)
171 mmodule
.objc_file
.add_local_function fc
175 # Calls withing Objective-C code
176 private fun objc_call_context
: ObjCCallContext do return once
new ObjCCallContext
178 # Calls from C to Objective-C
179 private fun to_objc_call_context
: ToObjCCallContext do return once
new ToObjCCallContext
181 # Calls from Objective-C to C
182 private fun from_objc_call_context
: FromObjCCallContext do return once
new FromObjCCallContext
184 private class ObjCCallContext
187 redef fun name_mtype
(mtype
)
189 if mtype
isa MClassType then
190 var ftype
= mtype
.mclass
.ftype
191 if ftype
isa ForeignObjCType then
192 return ftype
.objc_type
200 private class ToObjCCallContext
201 super ObjCCallContext
203 redef fun cast_to
(mtype
, name
)
205 if mtype
isa MClassType and mtype
.mclass
.ftype
isa ForeignObjCType then
206 return "(void*)({name})"
211 private class FromObjCCallContext
212 super ObjCCallContext
214 redef fun cast_from
(mtype
, name
)
216 if mtype
isa MClassType and mtype
.mclass
.ftype
isa ForeignObjCType then
217 return "({name_mtype(mtype)})({name})"