2 * Copyright (C) 2005 Casper S. Hornstrup
3 * Copyright (C) 2008 Hervé Poussineau
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program 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
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "backend/backend.h"
29 Environment::GetVariable ( const string
& name
)
31 char* value
= getenv ( name
.c_str () );
32 if ( value
!= NULL
&& strlen ( value
) > 0 )
33 return ssprintf ( "%s",
40 Environment::GetArch ()
42 return GetEnvironmentVariablePathOrDefault ( "ROS_ARCH", "i386" );
46 Environment::GetEnvironmentVariablePathOrDefault ( const string
& name
,
47 const string
& defaultValue
)
49 const string
& environmentVariableValue
= Environment::GetVariable ( name
);
50 if ( environmentVariableValue
.length () > 0 )
51 return NormalizeFilename ( environmentVariableValue
);
57 Environment::GetIntermediatePath ()
59 string defaultIntermediate
=
60 string( "obj-" ) + GetArch ();
61 return GetEnvironmentVariablePathOrDefault ( "ROS_INTERMEDIATE",
62 defaultIntermediate
);
66 Environment::GetOutputPath ()
68 string defaultOutput
=
69 string( "output-" ) + GetArch ();
70 return GetEnvironmentVariablePathOrDefault ( "ROS_OUTPUT",
75 Environment::GetInstallPath ()
77 string defaultInstall
= GetCdOutputPath ();
78 return GetEnvironmentVariablePathOrDefault ( "ROS_INSTALL",
83 Environment::GetCdOutputPath ()
85 return GetEnvironmentVariablePathOrDefault ( "ROS_CDOUTPUT",
90 Environment::GetAutomakeFile ( const std::string
& defaultFile
)
92 return GetEnvironmentVariablePathOrDefault ( "ROS_AUTOMAKE",
96 ParseContext::ParseContext ()
97 : compilationUnit (NULL
)
102 FileLocation::FileLocation ( const DirectoryLocation directory
,
103 const std::string
& relative_path
,
104 const std::string
& name
,
105 const XMLElement
*node
)
106 : directory ( directory
),
107 relative_path ( NormalizeFilename ( relative_path
) ),
110 if ( relative_path
[0] == '/' ||
111 relative_path
[0] == '\\' ||
112 relative_path
.find ( '$' ) != string::npos
||
113 ( relative_path
.length () > 1 && ( relative_path
[1] == ':' ||
114 relative_path
.find_last_of ( "/\\" ) == relative_path
.length () - 1 ) ) ||
115 ( relative_path
.length () > 3 && relative_path
.find ( ':' ) != string::npos
)
119 throw InvalidOperationException ( __FILE__
,
121 "Invalid relative path '%s' at %s",
122 relative_path
.c_str (),
123 node
->location
.c_str () );
125 throw InvalidOperationException ( __FILE__
,
127 "Invalid relative path '%s'",
128 relative_path
.c_str () );
131 if ( name
.find_first_of ( "/\\:" ) != string::npos
)
134 throw InvalidOperationException ( __FILE__
,
136 "Invalid file name '%s' at %s",
138 node
->location
.c_str () );
140 throw InvalidOperationException ( __FILE__
,
142 "Invalid file name '%s'",
148 FileLocation::FileLocation ( const FileLocation
& other
)
149 : directory ( other
.directory
),
150 relative_path ( other
.relative_path
),
156 Project::Project ( const Configuration
& configuration
,
157 const string
& filename
,
158 const std::map
<std::string
, std::string
>* properties
)
159 : xmlfile (filename
),
162 configuration (configuration
)
168 std::map
<string
, string
>::const_iterator it
;
169 for (it
= properties
->begin (); it
!= properties
->end (); it
++)
171 const Property
*existing
= LookupProperty( it
->first
);
174 Property
* property
= new Property ( *this, NULL
, it
->first
, it
->second
);
175 non_if_data
.properties
.push_back (property
);
188 #ifdef NOT_NEEDED_SINCE_THESE_ARE_CLEANED_BY_IFABLE_DATA
189 for ( i
= 0; i
< modules
.size (); i
++ )
192 for ( i
= 0; i
< linkerFlags
.size (); i
++ )
193 delete linkerFlags
[i
];
194 for ( i
= 0; i
< cdfiles
.size (); i
++ )
196 for ( i
= 0; i
< installfiles
.size (); i
++ )
197 delete installfiles
[i
];
203 Project::LookupProperty ( const string
& name
) const
205 for ( size_t i
= 0; i
< non_if_data
.properties
.size (); i
++ )
207 const Property
* property
= non_if_data
.properties
[i
];
208 if ( property
->name
== name
)
215 Project::ResolveNextProperty ( const string
& s
) const
217 size_t i
= s
.find ( "${" );
218 if ( i
== string::npos
)
220 if ( i
!= string::npos
)
223 if ( s
[i
+ 1] == '{' )
227 size_t j
= s
.find ( endCharacter
);
228 if ( j
!= string::npos
)
230 int propertyNameLength
= j
- i
- 2;
231 string propertyName
= s
.substr ( i
+ 2, propertyNameLength
);
232 const Property
* property
= LookupProperty ( propertyName
);
233 if ( property
!= NULL
)
234 return string ( s
).replace ( i
, propertyNameLength
+ 3, property
->value
);
241 Project::ResolveProperties ( const string
& s
) const
248 s2
= ResolveNextProperty ( s3
);
249 } while ( s2
!= s3
);
254 Project::SetConfigurationOption ( char* s
,
256 string alternativeName
)
258 const Property
* property
= LookupProperty ( name
);
259 if ( property
!= NULL
&& property
->value
.length () > 0 )
263 property
->name
.c_str (),
264 property
->value
.c_str () );
266 else if ( property
!= NULL
)
270 property
->name
.c_str () );
272 else if ( !alternativeName
.empty() )
276 alternativeName
.c_str () );
281 Project::SetConfigurationOption ( char* s
,
284 SetConfigurationOption ( s
, name
, "" );
288 Project::WriteConfigurationFile ()
293 buf
= (char*) malloc ( 10*1024 );
295 throw OutOfMemoryException ();
298 s
= s
+ sprintf ( s
, "/* Automatically generated. " );
299 s
= s
+ sprintf ( s
, "Edit config.xml to change configuration */\n" );
300 s
= s
+ sprintf ( s
, "#ifndef __INCLUDE_CONFIG_H\n" );
301 s
= s
+ sprintf ( s
, "#define __INCLUDE_CONFIG_H\n" );
303 SetConfigurationOption ( s
, "ARCH" );
304 SetConfigurationOption ( s
, "OPTIMIZED" );
305 SetConfigurationOption ( s
, "MP", "UP");
306 SetConfigurationOption ( s
, "ACPI" );
307 SetConfigurationOption ( s
, "_3GB" );
309 s
= s
+ sprintf ( s
, "#endif /* __INCLUDE_CONFIG_H */\n" );
311 FileSupportCode::WriteIfChanged ( buf
, Environment::GetIntermediatePath() + sSep
+ "include" + sSep
+ "roscfg.h" );
317 Project::ExecuteInvocations ()
319 for ( size_t i
= 0; i
< modules
.size (); i
++ )
320 modules
[i
]->InvokeModule ();
327 head
= XMLLoadFile ( xmlfile
, path
, xmlbuildfiles
);
329 for ( size_t i
= 0; i
< head
->subElements
.size (); i
++ )
331 if ( head
->subElements
[i
]->name
== "project" )
333 node
= head
->subElements
[i
];
341 node
= head
->subElements
[0];
343 throw XMLInvalidBuildFileException (
345 "Document contains no 'project' tag." );
349 Project::ProcessXML ( const string
& path
)
351 const XMLAttribute
*att
;
352 if ( node
->name
!= "project" )
353 throw Exception ( "internal tool error: Project::ProcessXML() called with non-<project> node" );
355 att
= node
->GetAttribute ( "name", false );
361 att
= node
->GetAttribute ( "makefile", true );
363 makefile
= Environment::GetAutomakeFile ( att
->value
);
366 for ( i
= 0; i
< node
->subElements
.size (); i
++ )
368 ParseContext parseContext
;
369 ProcessXMLSubElement ( *node
->subElements
[i
], path
, parseContext
);
372 non_if_data
.ProcessXML ();
374 non_if_data
.ExtractModules( modules
);
376 for ( i
= 0; i
< linkerFlags
.size (); i
++ )
377 linkerFlags
[i
]->ProcessXML ();
378 for ( i
= 0; i
< modules
.size (); i
++ )
379 modules
[i
]->ProcessXML ();
380 for ( i
= 0; i
< cdfiles
.size (); i
++ )
381 cdfiles
[i
]->ProcessXML ();
382 for ( i
= 0; i
< installfiles
.size (); i
++ )
383 installfiles
[i
]->ProcessXML ();
387 Project::ProcessXMLSubElement ( const XMLElement
& e
,
389 ParseContext
& parseContext
)
391 bool subs_invalid
= false;
393 string
subpath(path
);
394 if ( e
.name
== "module" )
396 Module
* module
= new Module ( *this, e
, path
);
397 if ( LocateModule ( module
->name
) )
398 throw XMLInvalidBuildFileException (
400 "module name conflict: '%s' (originally defined at %s)",
401 module
->name
.c_str(),
402 module
->node
.location
.c_str() );
403 non_if_data
.modules
.push_back ( module
);
404 return; // defer processing until later
406 else if ( e
.name
== "cdfile" )
408 CDFile
* cdfile
= new CDFile ( *this, e
, path
);
409 cdfiles
.push_back ( cdfile
);
412 else if ( e
.name
== "installfile" )
414 InstallFile
* installfile
= new InstallFile ( *this, e
, path
);
415 installfiles
.push_back ( installfile
);
418 else if ( e
.name
== "directory" )
420 const XMLAttribute
* att
= e
.GetAttribute ( "name", true );
422 subpath
= GetSubPath ( *this, e
.location
, path
, att
->value
);
424 else if ( e
.name
== "include" )
426 Include
* include
= new Include ( *this, &e
);
427 non_if_data
.includes
.push_back ( include
);
430 else if ( e
.name
== "define" )
432 Define
* define
= new Define ( *this, e
);
433 non_if_data
.defines
.push_back ( define
);
436 else if ( e
.name
== "compilerflag" )
438 CompilerFlag
* pCompilerFlag
= new CompilerFlag ( *this, e
);
439 non_if_data
.compilerFlags
.push_back ( pCompilerFlag
);
442 else if ( e
.name
== "linkerflag" )
444 linkerFlags
.push_back ( new LinkerFlag ( *this, e
) );
447 else if ( e
.name
== "if" || e
.name
== "ifnot" )
449 const XMLAttribute
* name
;
450 name
= e
.GetAttribute ( "property", true );
452 const Property
*property
= LookupProperty( name
->value
);
455 // Property not found
456 throw InvalidOperationException ( __FILE__
,
458 "Test on unknown property '%s' at %s",
459 name
->value
.c_str (), e
.location
.c_str () );
462 const XMLAttribute
* value
;
463 value
= e
.GetAttribute ( "value", true );
466 bool negate
= ( e
.name
== "ifnot" );
467 bool equality
= ( property
->value
== value
->value
);
468 if ( equality
== negate
)
470 // Failed, skip this element
471 if ( configuration
.Verbose
)
472 printf("Skipping 'If' at %s\n", e
.location
.c_str () );
475 subs_invalid
= false;
477 else if ( e
.name
== "property" )
479 Property
* property
= new Property ( e
, *this, NULL
);
480 non_if_data
.properties
.push_back ( property
);
482 if ( subs_invalid
&& e
.subElements
.size() )
484 throw XMLInvalidBuildFileException (
486 "<%s> cannot have sub-elements",
489 for ( size_t i
= 0; i
< e
.subElements
.size (); i
++ )
490 ProcessXMLSubElement ( *e
.subElements
[i
], subpath
, parseContext
);
494 Project::LocateModule ( const string
& name
)
496 for ( size_t i
= 0; i
< modules
.size (); i
++ )
498 if (modules
[i
]->name
== name
)
506 Project::LocateModule ( const string
& name
) const
508 for ( size_t i
= 0; i
< modules
.size (); i
++ )
510 if ( modules
[i
]->name
== name
)
518 Project::GetProjectFilename () const