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 expr
isa AStringFormExpr then
62 var text
= expr
.collect_text
63 text
= text
.substring
(1, text
.length-2
)
64 var opt
= new DirectCCompilerOption(text
)
66 else if expr
isa ACallExpr then
67 # We support calls to "exec" only
68 var exec_args
= expr
.n_args
.to_a
69 if expr
.n_id
.text
!= "exec" or exec_args
.is_empty
then
70 modelbuilder
.error
(nat
, "Syntax error: \"{annotation_name}\
" accepts only calls to `exec` with the command as arguments.")
74 var exec_args_as_strings
= new Array[String]
75 for exec_arg
in exec_args
do
76 if not exec_arg
isa AStringFormExpr then
77 modelbuilder
.error
(nat
, "Syntax error: calls to `exec` expects the arguments to be String literals.")
80 var arg_string
= exec_arg
.collect_text
81 arg_string
= arg_string
.substring
(1, arg_string
.length-2
)
82 exec_args_as_strings
.add
(arg_string
)
86 var opt
= new ExecCCompilerOption(exec_args_as_strings
, expr
)
89 modelbuilder
.error
(nat
, "Syntax error: \"{annotation_name}\
" expects its arguments to be the name of the package as String literals.")
94 # process calls to external command
95 var simplified_options
= new Array[DirectCCompilerOption]
97 if opt
isa ExecCCompilerOption then
98 # prepare to execute command
99 var cmd_args
= opt
.command
101 if cmd_args
.length
== 1 then
102 proc
= new IProcess.from_a
(cmd_args
[0], new Array[String])
103 else if cmd_args
.length
> 1 then
104 var rest_args
= cmd_args
.subarray
(1, cmd_args
.length-1
)
105 proc
= new IProcess.from_a
(cmd_args
[0], rest_args
)
108 # wait for its completion
112 var status
= proc
.status
114 modelbuilder
.error
(opt
.exec_node
, "Annotation error: Something went wrong executing the argument of annotation \"{annotation_name}\
", make sure the command is valid.")
119 var result
= proc
.read_all
.replace
("\n", " ")
120 if result
.is_empty
then
121 modelbuilder
.error
(opt
.exec_node
, "Annotation error: Got no result from the command, make sure it is valid.")
124 simplified_options
.add
(new DirectCCompilerOption(result
))
126 assert opt
isa DirectCCompilerOption
127 simplified_options
.add
(opt
)
132 var mmodule
= nmoduledecl
.parent
.as(AModule).mmodule
.as(not null)
134 for opt
in simplified_options
do
136 if annotation_name
== compiler_annotation_name
then
137 process_c_compiler_annotation
(mmodule
, cmd
)
138 else if annotation_name
== linker_annotation_name
then
139 process_c_linker_annotation
(mmodule
, cmd
)
140 else if annotation_name
== cpp_compiler_annotation_name
then
141 process_cpp_compiler_annotation
(mmodule
, cmd
)
146 fun process_c_compiler_annotation
(mmodule
: MModule, opt
: String)
148 mmodule
.c_compiler_options
= "{mmodule.c_compiler_options} {opt}"
151 fun process_c_linker_annotation
(mmodule
: MModule, opt
: String)
153 mmodule
.c_linker_options
= "{mmodule.c_linker_options} {opt}"
156 fun process_cpp_compiler_annotation
(mmodule
: MModule, opt
: String)
158 mmodule
.cpp_compiler_options
= "{mmodule.cpp_compiler_options} {opt}"
162 abstract class CCompilerOption
165 class DirectCCompilerOption
166 super CCompilerOption
171 class ExecCCompilerOption
172 super CCompilerOption
174 var command
: Array[String]
175 var exec_node
: ACallExpr