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 redef class ToolContext
25 var c_compiler_options_phase
: Phase = new CCompilerOptionsPhase(self, null)
28 private class CCompilerOptionsPhase
31 fun compiler_annotation_name
: String do return "c_compiler_option"
32 fun linker_annotation_name
: String do return "c_linker_option"
34 redef fun process_annotated_node
(nmoduledecl
, nat
)
36 # Skip if we are not interested
37 var annotation_name
= nat
.n_atid
.n_id
.text
38 if annotation_name
!= compiler_annotation_name
and
39 annotation_name
!= linker_annotation_name
then return
41 # Do some validity checks and print errors if the annotation is used incorrectly
42 var modelbuilder
= toolcontext
.modelbuilder
44 if not nmoduledecl
isa AModuledecl then
45 modelbuilder
.error
(nat
, "Syntax error: only the declaration of modules may use \"{annotation_name}\
".")
51 modelbuilder
.error
(nat
, "Syntax error: \"{annotation_name}\
" expects at least one argument.")
55 var options
= new Array[CCompilerOption]
57 if not arg
isa AExprAtArg then
58 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\
")`.")
63 if expr
isa AStringFormExpr then
64 var text
= expr
.collect_text
65 text
= text
.substring
(1, text
.length-2
)
66 var opt
= new DirectCCompilerOption(text
)
68 else if expr
isa ACallExpr then
69 # We support calls to "exec" only
70 var exec_args
= expr
.n_args
.to_a
71 if expr
.n_id
.text
!= "exec" or exec_args
.is_empty
then
72 modelbuilder
.error
(nat
, "Syntax error: \"{annotation_name}\
" accepts only calls to `exec` with the command as arguments.")
76 var exec_args_as_strings
= new Array[String]
77 for exec_arg
in exec_args
do
78 if not exec_arg
isa AStringFormExpr then
79 modelbuilder
.error
(nat
, "Syntax error: calls to `exec` expects the arguments to be String literals.")
82 var arg_string
= exec_arg
.collect_text
83 arg_string
= arg_string
.substring
(1, arg_string
.length-2
)
84 exec_args_as_strings
.add
(arg_string
)
88 var opt
= new ExecCCompilerOption(exec_args_as_strings
, expr
)
91 modelbuilder
.error
(nat
, "Syntax error: \"{annotation_name}\
" expects its arguments to be the name of the package as String literals.")
96 # process calls to external command
97 var simplified_options
= new Array[DirectCCompilerOption]
99 if opt
isa ExecCCompilerOption then
100 # prepare to execute command
101 var cmd_args
= opt
.command
103 if cmd_args
.length
== 1 then
104 proc
= new IProcess.from_a
(cmd_args
[0], new Array[String])
105 else if cmd_args
.length
> 1 then
106 var rest_args
= cmd_args
.subarray
(1, cmd_args
.length-1
)
107 proc
= new IProcess.from_a
(cmd_args
[0], rest_args
)
110 # wait for its completion
114 var status
= proc
.status
116 modelbuilder
.error
(opt
.exec_node
, "Annotation error: Something went wrong executing the argument of annotation \"{annotation_name}\
", make sure the command is valid.")
121 var result
= proc
.read_all
.replace
("\n", " ")
122 if result
.is_empty
then
123 modelbuilder
.error
(opt
.exec_node
, "Annotation error: Got no result from the command, make sure it is valid.")
126 simplified_options
.add
(new DirectCCompilerOption(result
))
128 assert opt
isa DirectCCompilerOption
129 simplified_options
.add
(opt
)
134 var nmodule
= nmoduledecl
.parent
.as(AModule)
136 for opt
in simplified_options
do
138 if annotation_name
== compiler_annotation_name
then
139 process_c_compiler_annotation
(nmodule
, cmd
)
140 else if annotation_name
== linker_annotation_name
then
141 process_c_linker_annotation
(nmodule
, cmd
)
146 fun process_c_compiler_annotation
(nmodule
: AModule, opt
: String)
148 nmodule
.c_compiler_options
= "{nmodule.c_compiler_options} {opt}"
151 fun process_c_linker_annotation
(nmodule
: AModule, opt
: String)
153 nmodule
.c_linker_options
= "{nmodule.c_linker_options} {opt}"
157 abstract class CCompilerOption
160 class DirectCCompilerOption
161 super CCompilerOption
164 init (opt
: String) do option
= opt
167 class ExecCCompilerOption
168 super CCompilerOption
170 var command
: Array[String]
171 var exec_node
: ACallExpr
173 init (command
: Array[String], exec_node
: ACallExpr)
175 self.command
= command
176 self.exec_node
= exec_node