1 /* valacodecontext.vala
3 * Copyright (C) 2006-2007 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Jürg Billeter <j@bitron.ch>
26 * The root of the code tree.
28 public class Vala
.CodeContext
{
30 * Specifies the name of the library to be built.
32 * Public header files of a library will be assumed to be installed in
33 * a subdirectory named like the library.
35 public string library
{ get; set; }
38 * Enable automatic memory management.
40 public bool memory_management
{ get; set; }
43 * Enable run-time checks for programming errors.
45 public bool assert
{ get; set; }
48 * Enable additional run-time checks.
50 public bool checking
{ get; set; }
53 * Output C code, don't compile to object code.
55 public bool ccode_only
{ get; set; }
58 * Compile but do not link.
60 public bool compile_only
{ get; set; }
65 public string output
{ get; set; }
68 * Produce debug information.
70 public bool debug
{ get; set; }
75 public int optlevel
{ get; set; }
78 * Specifies the optional module initialization method.
80 public Method module_init_method
{ get; set; }
82 List
<SourceFile
> source_files
;
83 private Symbol
! root
= new
Symbol ();
85 List
<SourceFileCycle
> cycles
;
87 private List
<string> packages
;
90 * Returns the root symbol of the code tree.
94 public Symbol
! get_root () {
99 * Returns a copy of the list of source files.
101 * @return list of source files
103 public List
<weak SourceFile
> get_source_files () {
104 return source_files
.copy ();
108 * Adds the specified file to the list of source files.
110 * @param file a source file
112 public void add_source_file (SourceFile
! file
) {
113 source_files
.append (file
);
117 * Returns a copy of the list of used packages.
119 * @return list of used packages
121 public List
<weak string> get_packages () {
122 return packages
.copy ();
126 * Returns whether the specified package is being used.
128 * @param pkg a package name
129 * @return true if the specified package is being used
131 public bool has_package (string! pkg
) {
132 return packages
.find_custom (pkg
, strcmp
) != null;
136 * Adds the specified package to the list of used packages.
138 * @param pkg a package name
140 public void add_package (string! pkg
) {
141 packages
.append (pkg
);
145 * Visits the complete code tree file by file.
147 * @param visitor the visitor to be called when traversing
149 public void accept (CodeVisitor
! visitor
) {
150 foreach (SourceFile file
in source_files
) {
151 file
.accept (visitor
);
156 * Find and resolve cycles in source file dependencies.
158 public void find_header_cycles () {
159 /* find cycles in dependencies between source files */
160 foreach (SourceFile file
in source_files
) {
161 /* we're only interested in internal source files */
166 if (file
.mark
== 0) {
171 /* find one head for each cycle, it must not have any
172 * hard dependencies on other files in the cycle
174 foreach (SourceFileCycle cycle
in cycles
) {
175 cycle
.head
= find_cycle_head ((SourceFile
) cycle
.files
.data
);
176 cycle
.head
.is_cycle_head
= true;
179 /* connect the source files in a non-cyclic way
180 * cycle members connect to the head of their cycle
182 foreach (SourceFile file2
in source_files
) {
183 /* we're only interested in internal source files */
188 foreach (SourceFile dep
in file2
.get_header_internal_dependencies ()) {
189 if (file2
.cycle
!= null && dep
.cycle
== file2
.cycle
) {
190 /* in the same cycle */
191 if (!file2
.is_cycle_head
) {
192 /* include header of cycle head */
193 file2
.add_header_internal_include (file2
.cycle
.head
.get_cinclude_filename ());
196 /* we can just include the headers if they are not in a cycle or not in the same cycle as the current file */
197 file2
.add_header_internal_include (dep
.get_cinclude_filename ());
204 private weak SourceFile
find_cycle_head (SourceFile
! file
) {
205 foreach (SourceFile dep
in file
.get_header_internal_full_dependencies ()) {
207 /* ignore file-internal dependencies */
211 foreach (SourceFile cycle_file
in file
.cycle
.files
) {
212 if (dep
== cycle_file
) {
213 return find_cycle_head (dep
);
217 /* no hard dependencies on members of the same cycle found
218 * source file suitable as cycle head
223 private void visit (SourceFile
! file
, List
<SourceFile
> chain
) {
224 /* no deep copy available yet
225 * var l = chain.copy ();
227 List
<weak SourceFile
> l
= null;
228 foreach (SourceFile chain_file
in chain
) {
229 l
.append (chain_file
);
234 /* mark file as currently being visited */
237 foreach (SourceFile dep
in file
.get_header_internal_dependencies ()) {
245 var cycle
= new
SourceFileCycle ();
246 cycles
.append (cycle
);
248 bool cycle_start_found
= false;
249 foreach (SourceFile cycle_file
in l
) {
250 SourceFileCycle ref_cycle_file_cycle
= cycle_file
.cycle
;
251 if (!cycle_start_found
) {
252 if (cycle_file
== dep
) {
253 cycle_start_found
= true;
257 if (!cycle_start_found
) {
261 if (cycle_file
.cycle
!= null) {
262 /* file already in a cycle */
264 if (cycle_file
.cycle
== cycle
) {
265 /* file is in the same cycle, nothing to do */
269 /* file is in an other cycle, merge the two cycles */
271 /* broken memory management cycles.remove (cycle_file.cycle); */
272 List
<weak SourceFileCycle
> newlist
= null;
273 foreach (SourceFileCycle oldcycle
in cycles
) {
274 if (oldcycle
!= cycle_file
.cycle
) {
275 newlist
.append (oldcycle
);
279 foreach (SourceFileCycle newcycle
in newlist
) {
280 cycles
.append (newcycle
);
283 /* end workaround for broken memory management */
285 foreach (SourceFile inner_cycle_file
in cycle_file
.cycle
.files
) {
286 if (inner_cycle_file
.cycle
!= cycle
) {
287 /* file in inner cycle not yet added to outer cycle */
288 cycle
.files
.append (inner_cycle_file
);
289 inner_cycle_file
.cycle
= cycle
;
293 cycle
.files
.append (cycle_file
);
294 cycle_file
.cycle
= cycle
;
297 } else if (dep
.mark
== 0) {
298 /* found not yet visited file */
304 /* mark file as successfully visited */