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 along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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::GetSourcePath ()
69 getcwd(temp
, _MAX_PATH
);
74 Environment::GetOutputPath ()
76 string defaultOutput
=
77 string( "output-" ) + GetArch ();
78 return GetEnvironmentVariablePathOrDefault ( "ROS_OUTPUT",
83 Environment::GetInstallPath ()
85 string defaultInstall
= GetCdOutputPath ();
86 return GetEnvironmentVariablePathOrDefault ( "ROS_INSTALL",
91 Environment::GetCdOutputPath ()
93 return GetEnvironmentVariablePathOrDefault ( "ROS_CDOUTPUT",
98 Environment::GetAutomakeFile ( const std::string
& defaultFile
)
100 return GetEnvironmentVariablePathOrDefault ( "ROS_AUTOMAKE",
104 ParseContext::ParseContext ()
105 : compilationUnit (NULL
)
110 FileLocation::FileLocation ( const DirectoryLocation directory
,
111 const std::string
& relative_path
,
112 const std::string
& name
,
113 const XMLElement
*node
)
114 : directory ( directory
),
115 relative_path ( NormalizeFilename ( relative_path
) ),
118 if ( relative_path
[0] == '/' ||
119 relative_path
[0] == '\\' ||
120 relative_path
.find ( '$' ) != string::npos
||
121 ( relative_path
.length () > 1 && ( relative_path
[1] == ':' ||
122 relative_path
.find_last_of ( "/\\" ) == relative_path
.length () - 1 ) ) ||
123 ( relative_path
.length () > 3 && relative_path
.find ( ':' ) != string::npos
)
127 throw InvalidOperationException ( __FILE__
,
129 "Invalid relative path '%s' at %s",
130 relative_path
.c_str (),
131 node
->location
.c_str () );
133 throw InvalidOperationException ( __FILE__
,
135 "Invalid relative path '%s'",
136 relative_path
.c_str () );
139 if ( name
.find_first_of ( "/\\:" ) != string::npos
)
142 throw InvalidOperationException ( __FILE__
,
144 "Invalid file name '%s' at %s",
146 node
->location
.c_str () );
148 throw InvalidOperationException ( __FILE__
,
150 "Invalid file name '%s'",
156 FileLocation::FileLocation ( const FileLocation
& other
)
157 : directory ( other
.directory
),
158 relative_path ( other
.relative_path
),
164 Project::Project ( const Configuration
& configuration
,
165 const string
& filename
,
166 const std::map
<std::string
, std::string
>* properties
)
167 : xmlfile (filename
),
170 configuration (configuration
)
176 std::map
<string
, string
>::const_iterator it
;
177 for (it
= properties
->begin (); it
!= properties
->end (); it
++)
179 const Property
*existing
= LookupProperty( it
->first
);
182 Property
* property
= new Property ( *this, NULL
, it
->first
, it
->second
);
183 non_if_data
.properties
.insert ( std::make_pair ( property
->name
, property
) );
196 #ifdef NOT_NEEDED_SINCE_THESE_ARE_CLEANED_BY_IFABLE_DATA
197 for ( i
= 0; i
< modules
.size (); i
++ )
200 for ( i
= 0; i
< linkerFlags
.size (); i
++ )
201 delete linkerFlags
[i
];
202 for ( i
= 0; i
< cdfiles
.size (); i
++ )
204 for ( i
= 0; i
< installfiles
.size (); i
++ )
205 delete installfiles
[i
];
211 Project::LookupProperty ( const string
& name
) const
213 std::map
<std::string
, Property
*>::const_iterator p
= non_if_data
.properties
.find(name
);
215 if ( p
== non_if_data
.properties
.end () )
222 Project::ResolveNextProperty ( const string
& s
) const
224 size_t i
= s
.find ( "${" );
225 if ( i
== string::npos
)
227 if ( i
!= string::npos
)
230 if ( s
[i
+ 1] == '{' )
234 size_t j
= s
.find ( endCharacter
);
235 if ( j
!= string::npos
)
237 int propertyNameLength
= j
- i
- 2;
238 string propertyName
= s
.substr ( i
+ 2, propertyNameLength
);
239 const Property
* property
= LookupProperty ( propertyName
);
240 if ( property
!= NULL
)
241 return string ( s
).replace ( i
, propertyNameLength
+ 3, property
->value
);
248 Project::ResolveProperties ( const string
& s
) const
255 s2
= ResolveNextProperty ( s3
);
256 } while ( s2
!= s3
);
261 Project::ExecuteInvocations ()
263 for( std::map
<std::string
, Module
*>::const_iterator p
= modules
.begin(); p
!= modules
.end(); ++ p
)
264 p
->second
->InvokeModule ();
271 head
= XMLLoadFile ( xmlfile
, path
, xmlbuildfiles
);
273 for ( size_t i
= 0; i
< head
->subElements
.size (); i
++ )
275 if ( head
->subElements
[i
]->name
== "project" )
277 node
= head
->subElements
[i
];
285 node
= head
->subElements
[0];
287 throw XMLInvalidBuildFileException (
289 "Document contains no 'project' tag." );
293 Project::ProcessXML ( const string
& path
)
295 const XMLAttribute
*att
;
296 if ( node
->name
!= "project" )
297 throw Exception ( "internal tool error: Project::ProcessXML() called with non-<project> node" );
299 att
= node
->GetAttribute ( "name", false );
305 att
= node
->GetAttribute ( "makefile", true );
307 makefile
= Environment::GetAutomakeFile ( att
->value
);
309 att
= node
->GetAttribute ( "allowwarnings", false );
310 allowWarningsSet
= att
!= NULL
;
312 allowWarnings
= att
->value
== "true";
315 for ( i
= 0; i
< node
->subElements
.size (); i
++ )
317 ParseContext parseContext
;
318 ProcessXMLSubElement ( *node
->subElements
[i
], path
, parseContext
);
321 non_if_data
.ProcessXML ();
322 host_non_if_data
.ProcessXML ();
324 non_if_data
.ExtractModules( modules
);
326 for ( i
= 0; i
< linkerFlags
.size (); i
++ )
327 linkerFlags
[i
]->ProcessXML ();
328 for( std::map
<std::string
, Module
*>::const_iterator p
= modules
.begin(); p
!= modules
.end(); ++ p
)
329 p
->second
->ProcessXML ();
330 for ( i
= 0; i
< cdfiles
.size (); i
++ )
331 cdfiles
[i
]->ProcessXML ();
332 for ( i
= 0; i
< installfiles
.size (); i
++ )
333 installfiles
[i
]->ProcessXML ();
337 Project::ProcessXMLSubElement ( const XMLElement
& e
,
339 ParseContext
& parseContext
)
341 const XMLAttribute
* att
;
343 att
= e
.GetAttribute ( "compilerset", false );
347 CompilerSet compilerSet
;
349 if ( att
->value
== "msc" )
350 compilerSet
= MicrosoftC
;
351 else if ( att
->value
== "gcc" )
352 compilerSet
= GnuGcc
;
354 throw InvalidAttributeValueException (
359 if ( compilerSet
!= configuration
.Compiler
)
363 att
= e
.GetAttribute ( "linkerset", false );
369 if ( att
->value
== "mslink" )
370 linkerSet
= MicrosoftLink
;
371 else if ( att
->value
== "ld" )
374 throw InvalidAttributeValueException (
379 if ( linkerSet
!= configuration
.Linker
)
383 bool subs_invalid
= false;
385 string
subpath(path
);
386 if ( e
.name
== "module" )
388 Module
* module
= new Module ( *this, e
, path
);
389 if ( LocateModule ( module
->name
) )
390 throw XMLInvalidBuildFileException (
392 "module name conflict: '%s' (originally defined at %s)",
393 module
->name
.c_str(),
394 module
->node
.location
.c_str() );
395 non_if_data
.modules
.push_back ( module
);
396 return; // defer processing until later
398 else if ( e
.name
== "cdfile" )
400 CDFile
* cdfile
= new CDFile ( *this, e
, path
);
401 cdfiles
.push_back ( cdfile
);
404 else if ( e
.name
== "installfile" )
406 InstallFile
* installfile
= new InstallFile ( *this, e
, path
);
407 installfiles
.push_back ( installfile
);
410 else if ( e
.name
== "directory" )
412 const XMLAttribute
* att
= e
.GetAttribute ( "name", true );
414 subpath
= GetSubPath ( *this, e
.location
, path
, att
->value
);
416 else if ( e
.name
== "include" )
418 const XMLAttribute
* host
= e
.GetAttribute("host", false);
419 Include
* include
= new Include ( *this, &e
);
421 if(host
&& host
->value
== "true")
422 host_non_if_data
.includes
.push_back(include
);
424 non_if_data
.includes
.push_back ( include
);
428 else if ( e
.name
== "define" || e
.name
== "redefine" )
430 const XMLAttribute
* host
= e
.GetAttribute("host", false);
431 Define
* define
= new Define ( *this, e
);
433 if(host
&& host
->value
== "true")
434 host_non_if_data
.defines
.push_back(define
);
436 non_if_data
.defines
.push_back ( define
);
440 else if ( e
.name
== "compilerflag" )
442 CompilerFlag
* pCompilerFlag
= new CompilerFlag ( *this, e
);
443 non_if_data
.compilerFlags
.push_back ( pCompilerFlag
);
446 else if ( e
.name
== "linkerflag" )
448 linkerFlags
.push_back ( new LinkerFlag ( *this, e
) );
451 else if ( e
.name
== "if" || e
.name
== "ifnot" )
453 const XMLAttribute
* name
;
454 name
= e
.GetAttribute ( "property", true );
456 const Property
*property
= LookupProperty( name
->value
);
457 const string
*PropertyValue
;
458 const string EmptyString
;
462 PropertyValue
= &property
->value
;
466 // Property does not exist, treat it as being empty
467 PropertyValue
= &EmptyString
;
470 const XMLAttribute
* value
;
471 value
= e
.GetAttribute ( "value", true );
474 bool negate
= ( e
.name
== "ifnot" );
475 bool equality
= ( *PropertyValue
== value
->value
);
476 if ( equality
== negate
)
478 // Failed, skip this element
479 if ( configuration
.Verbose
)
480 printf("Skipping 'If' at %s\n", e
.location
.c_str () );
483 subs_invalid
= false;
485 else if ( e
.name
== "property" )
487 Property
* property
= new Property ( e
, *this, NULL
);
488 non_if_data
.properties
.insert ( std::make_pair ( property
->name
, property
) );
490 if ( subs_invalid
&& e
.subElements
.size() )
492 throw XMLInvalidBuildFileException (
494 "<%s> cannot have sub-elements",
497 for ( size_t i
= 0; i
< e
.subElements
.size (); i
++ )
498 ProcessXMLSubElement ( *e
.subElements
[i
], subpath
, parseContext
);
502 Project::LocateModule ( const string
& name
)
504 std::map
<std::string
, Module
*>::const_iterator p
= modules
.find(name
);
506 if ( p
== modules
.end() )
513 Project::LocateModule ( const string
& name
) const
515 std::map
<std::string
, Module
*>::const_iterator p
= modules
.find(name
);
517 if ( p
== modules
.end() )
524 Project::GetProjectFilename () const
530 Project::GetCompilerSet () const
532 switch ( configuration
.Compiler
)
534 case GnuGcc
: return "gcc";
535 case MicrosoftC
: return "msc";
536 default: assert ( false );
541 Project::GetLinkerSet () const
543 switch ( configuration
.Linker
)
545 case GnuLd
: return "ld";
546 case MicrosoftLink
: return "mslink";
547 default: assert ( false );