Merge: ldflags for Android
[nit.git] / src / ffi / c.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2012-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 # Support for nesting C code within a Nit program using its FFI
18 module c
19
20 import ffi_base
21
22 redef class FFILanguageAssignationPhase
23 var c_language: FFILanguage = new CLanguage(self)
24 end
25
26 class CLanguage
27 super FFILanguage
28
29 redef fun identify_language(n) do return n.is_c
30
31 redef fun compile_module_block(block, ecc, mmodule)
32 do
33 if block.is_c_header then
34 ecc.header_custom.add block.location.as_line_pragma
35 ecc.header_custom.add "\n"
36 ecc.header_custom.add block.code
37 else if block.is_c_body then
38 ecc.body_impl.add block.location.as_line_pragma
39 ecc.body_impl.add "\n"
40 ecc.body_impl.add block.code
41 end
42 end
43
44 redef fun compile_extern_method(block, m, ecc, mmodule)
45 do
46 var fc = new ExternCFunction(m, mmodule)
47 fc.decls.add( block.location.as_line_pragma )
48 fc.exprs.add( block.code )
49 ecc.add_exported_function( fc )
50 end
51
52 redef fun compile_extern_class(block, m, ecc, mmodule) do end
53
54 redef fun get_ftype(block, m) do return new ForeignCType(block.code)
55
56 redef fun compile_callback(callback, mmodule, mainmodule, ecc)
57 do
58 callback.compile_callback_to_c(mainmodule, ecc)
59 end
60 end
61
62 redef class AExternCodeBlock
63 fun is_c: Bool do return language_name == null or
64 language_name_lowered == "c" or language_name_lowered.has_prefix( "c " )
65
66 fun is_c_body: Bool do return language_name == null or
67 language_name_lowered == "c" or language_name_lowered == "c body"
68
69 fun is_c_header: Bool do return language_name_lowered == "c header"
70 end
71
72 redef class Location
73 fun as_line_pragma: String do return "#line {line_start-1} \"{file.filename}\"\n"
74 end
75
76 redef class MModule
77 # FIXME make nullable the key of `cflags`, `ldflags` and `cppflags` when
78 # supported by the bootstrap
79
80 # Custom options for the C compiler (CFLAGS)
81 var cflags = new MultiHashMap[String, String]
82
83 # Custom options for the C linker (LDFLAGS)
84 var ldflags = new MultiHashMap[String, String]
85
86 # Additional libraries needed for the compilation
87 # Will be used with pkg-config
88 var pkgconfigs = new Array[String]
89 end
90
91 class ForeignCType
92 super ForeignType
93
94 redef var ctype: String
95 end
96
97 redef class NitniCallback
98 fun compile_callback_to_c(mmodule: MModule, ffi_ccu: CCompilationUnit) do end
99 end
100
101 redef class Object
102 # Context when calling user C code from generated code
103 fun to_c_call_context: ToCCallContext do return once new ToCCallContext
104
105 # Context when calling generated code from user C code
106 fun from_c_call_context: FromCCallContext do return once new FromCCallContext
107 end
108
109 redef class MExplicitCall
110 redef fun compile_callback_to_c(mmodule, ffi_ccu)
111 do
112 var mproperty = mproperty.as(MMethod)
113
114 var full_cname = mproperty.build_cname(recv_mtype, mmodule, null, long_signature)
115 var friendly_cname = mproperty.build_cname(recv_mtype, mmodule, null, short_signature)
116 ffi_ccu.body_decl.add("#define {friendly_cname} {full_cname}\n")
117 end
118 end
119
120 # Context when calling user C code from generated code
121 class ToCCallContext
122 super CallContext
123
124 # TODO: private init because singleton instance (see `to_c_call_context`)
125
126 redef fun name_mtype(mtype)
127 do
128 if mtype isa MClassType and mtype.mclass.kind == extern_kind then return "void *"
129 return mtype.cname
130 end
131 end
132
133 # Context when calling generated code from user C code
134 class FromCCallContext
135 super CallContext
136
137 # TODO: private init because singleton instance (see `from_c_call_context`)
138
139 redef fun name_mtype(mtype) do return mtype.cname
140 end
141
142 class ExternCFunction
143 super CFunction
144
145 var method: AMethPropdef
146
147 init (method: AMethPropdef, mmodule: MModule)
148 do
149 self.method = method
150
151 var recv_mtype = method.mpropdef.mclassdef.bound_mtype
152 var csignature = method.mpropdef.mproperty.build_csignature(recv_mtype, mmodule, "___impl", long_signature, from_c_call_context)
153
154 super( csignature )
155 end
156 end