1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2013 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 # Offers the annotations `c_compiler_option` and `c_linker_option` to specify
18 # options for the C compiler directly or indirectly. Differs from the `pkgconfig`
19 # annotation by the separation of the options between the compiler and linker.
20 module c_compiler_options
24 private import annotation
26 redef class ToolContext
27 var c_compiler_options_phase
: Phase = new CCompilerOptionsPhase(self, null)
30 private class CCompilerOptionsPhase
33 fun compiler_annotation_name
: String do return "c_compiler_option"
34 fun linker_annotation_name
: String do return "c_linker_option"
35 fun cpp_compiler_annotation_name
: String do return "cpp_compiler_option"
37 redef fun process_annotated_node
(nmoduledecl
, nat
)
39 # Skip if we are not interested
40 var annotation_name
= nat
.name
41 if annotation_name
!= compiler_annotation_name
and
42 annotation_name
!= linker_annotation_name
and
43 annotation_name
!= cpp_compiler_annotation_name
then return
45 # Do some validity checks and print errors if the annotation is used incorrectly
46 var modelbuilder
= toolcontext
.modelbuilder
48 if not nmoduledecl
isa AModuledecl then
49 modelbuilder
.error
(nat
, "Syntax error: only the declaration of modules may use \"{annotation_name}\
".")
55 modelbuilder
.error
(nat
, "Syntax error: \"{annotation_name}\
" expects at least one argument.")
59 var options
= new Array[CCompilerOption]
61 if not arg
isa AExprAtArg then
62 modelbuilder
.error
(nat
, "Syntax error: \"{annotation_name}\
" expects its arguments to be the name of the package as String literals or a call to `exex(\"local_program\
")`.")
67 if expr
isa AStringFormExpr then
68 var text
= expr
.collect_text
69 text
= text
.substring
(1, text
.length-2
)
70 var opt
= new DirectCCompilerOption(text
)
72 else if expr
isa ACallExpr then
73 # We support calls to "exec" only
74 var exec_args
= expr
.n_args
.to_a
75 if expr
.n_id
.text
!= "exec" or exec_args
.is_empty
then
76 modelbuilder
.error
(nat
, "Syntax error: \"{annotation_name}\
" accepts only calls to `exec` with the command as arguments.")
80 var exec_args_as_strings
= new Array[String]
81 for exec_arg
in exec_args
do
82 if not exec_arg
isa AStringFormExpr then
83 modelbuilder
.error
(nat
, "Syntax error: calls to `exec` expects the arguments to be String literals.")
86 var arg_string
= exec_arg
.collect_text
87 arg_string
= arg_string
.substring
(1, arg_string
.length-2
)
88 exec_args_as_strings
.add
(arg_string
)
92 var opt
= new ExecCCompilerOption(exec_args_as_strings
, expr
)
95 modelbuilder
.error
(nat
, "Syntax error: \"{annotation_name}\
" expects its arguments to be the name of the package as String literals.")
100 # process calls to external command
101 var simplified_options
= new Array[DirectCCompilerOption]
102 for opt
in options
do
103 if opt
isa ExecCCompilerOption then
104 # prepare to execute command
105 var cmd_args
= opt
.command
107 if cmd_args
.length
== 1 then
108 proc
= new IProcess.from_a
(cmd_args
[0], new Array[String])
109 else if cmd_args
.length
> 1 then
110 var rest_args
= cmd_args
.subarray
(1, cmd_args
.length-1
)
111 proc
= new IProcess.from_a
(cmd_args
[0], rest_args
)
114 # wait for its completion
118 var status
= proc
.status
120 modelbuilder
.error
(opt
.exec_node
, "Annotation error: Something went wrong executing the argument of annotation \"{annotation_name}\
", make sure the command is valid.")
125 var result
= proc
.read_all
.replace
("\n", " ")
126 if result
.is_empty
then
127 modelbuilder
.error
(opt
.exec_node
, "Annotation error: Got no result from the command, make sure it is valid.")
130 simplified_options
.add
(new DirectCCompilerOption(result
))
132 assert opt
isa DirectCCompilerOption
133 simplified_options
.add
(opt
)
138 var mmodule
= nmoduledecl
.parent
.as(AModule).mmodule
.as(not null)
140 for opt
in simplified_options
do
142 if annotation_name
== compiler_annotation_name
then
143 process_c_compiler_annotation
(mmodule
, cmd
)
144 else if annotation_name
== linker_annotation_name
then
145 process_c_linker_annotation
(mmodule
, cmd
)
146 else if annotation_name
== cpp_compiler_annotation_name
then
147 process_cpp_compiler_annotation
(mmodule
, cmd
)
152 fun process_c_compiler_annotation
(mmodule
: MModule, opt
: String)
154 mmodule
.c_compiler_options
= "{mmodule.c_compiler_options} {opt}"
157 fun process_c_linker_annotation
(mmodule
: MModule, opt
: String)
159 mmodule
.c_linker_options
= "{mmodule.c_linker_options} {opt}"
162 fun process_cpp_compiler_annotation
(mmodule
: MModule, opt
: String)
164 mmodule
.cpp_compiler_options
= "{mmodule.cpp_compiler_options} {opt}"
168 abstract class CCompilerOption
171 class DirectCCompilerOption
172 super CCompilerOption
175 init (opt
: String) do option
= opt
178 class ExecCCompilerOption
179 super CCompilerOption
181 var command
: Array[String]
182 var exec_node
: ACallExpr
184 init (command
: Array[String], exec_node
: ACallExpr)
186 self.command
= command
187 self.exec_node
= exec_node