ENH: Patch from Maik to add preprocessor directive handling to Fortran dependency scanning. Also added -fpp flag to Intel Fortran compiler on Windows by default.

This commit is contained in:
Brad King 2008-01-09 10:30:11 -05:00
parent 09e309c3d0
commit b761da39c1
6 changed files with 259 additions and 22 deletions

View File

@ -7,6 +7,8 @@ ELSE(CMAKE_VERBOSE_MAKEFILE)
SET(CMAKE_CL_NOLOGO "/nologo") SET(CMAKE_CL_NOLOGO "/nologo")
ENDIF(CMAKE_VERBOSE_MAKEFILE) ENDIF(CMAKE_VERBOSE_MAKEFILE)
SET(CMAKE_Fortran_MODDIR_FLAG "-module:")
SET(CMAKE_Fortran_CREATE_SHARED_LIBRARY SET(CMAKE_Fortran_CREATE_SHARED_LIBRARY
"link ${CMAKE_CL_NOLOGO} ${CMAKE_START_TEMP_FILE} /out:<TARGET> /dll <LINK_FLAGS> <OBJECTS> <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}") "link ${CMAKE_CL_NOLOGO} ${CMAKE_START_TEMP_FILE} /out:<TARGET> /dll <LINK_FLAGS> <OBJECTS> <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}")
@ -17,7 +19,7 @@ SET(CMAKE_Fortran_CREATE_STATIC_LIBRARY "lib ${CMAKE_CL_NOLOGO} <LINK_FLAGS> /o
# compile a C++ file into an object file # compile a C++ file into an object file
SET(CMAKE_Fortran_COMPILE_OBJECT SET(CMAKE_Fortran_COMPILE_OBJECT
"<CMAKE_Fortran_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} /Fo<OBJECT> <FLAGS> -c <SOURCE>${CMAKE_END_TEMP_FILE}") "<CMAKE_Fortran_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} /fpp /Fo<OBJECT> <FLAGS> -c <SOURCE>${CMAKE_END_TEMP_FILE}")
SET(CMAKE_COMPILE_RESOURCE "rc <FLAGS> /fo<OBJECT> <SOURCE>") SET(CMAKE_COMPILE_RESOURCE "rc <FLAGS> /fo<OBJECT> <SOURCE>")

View File

@ -70,6 +70,7 @@ struct cmDependsFortranFile
struct cmDependsFortranParser_s struct cmDependsFortranParser_s
{ {
cmDependsFortranParser_s(cmDependsFortran* self, cmDependsFortranParser_s(cmDependsFortran* self,
std::set<std::string>& ppDefines,
cmDependsFortranSourceInfo& info); cmDependsFortranSourceInfo& info);
~cmDependsFortranParser_s(); ~cmDependsFortranParser_s();
@ -89,9 +90,9 @@ struct cmDependsFortranParser_s
bool InInterface; bool InInterface;
int OldStartcond; int OldStartcond;
bool InPPFalseBranch; std::set<std::string> PPDefinitions;
std::vector<bool> SkipToEnd; std::size_t InPPFalseBranch;
int StepI; std::stack<bool> SkipToEnd;
// Information about the parsed source. // Information about the parsed source.
cmDependsFortranSourceInfo& Info; cmDependsFortranSourceInfo& Info;
@ -130,14 +131,39 @@ public:
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmDependsFortran::cmDependsFortran(): cmDependsFortran::cmDependsFortran():
IncludePath(0), Internal(0) IncludePath(0), PPDefinitions(0), Internal(0)
{ {
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmDependsFortran::cmDependsFortran(std::vector<std::string> const& includes): cmDependsFortran
IncludePath(&includes), Internal(new cmDependsFortranInternals) ::cmDependsFortran(std::vector<std::string> const& includes,
std::vector<std::string> const& definitions):
IncludePath(&includes),
Internal(new cmDependsFortranInternals)
{ {
// translate i.e. -DFOO=BAR to FOO and add it to the list of defined
// preprocessor symbols
std::string def;
for(std::vector<std::string>::const_iterator
it = definitions.begin(); it != definitions.end(); ++it)
{
std::size_t match = it->find("-D");
if(match != std::string::npos)
{
std::size_t assignment = it->find("=");
if(assignment != std::string::npos)
{
std::size_t length = assignment - (match+2);
def = it->substr(match+2, length);
}
else
{
def = it->substr(match+2);
}
this->PPDefinitions.push_back(def);
}
}
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -171,8 +197,13 @@ bool cmDependsFortran::WriteDependencies(const char *src, const char *obj,
cmDependsFortranSourceInfo& info = cmDependsFortranSourceInfo& info =
this->Internal->CreateObjectInfo(obj, src); this->Internal->CreateObjectInfo(obj, src);
// Create the parser object. // Make a copy of the macros defined via ADD_DEFINITIONS
cmDependsFortranParser parser(this, info); std::set<std::string> ppDefines(this->PPDefinitions.begin(),
this->PPDefinitions.end());
// Create the parser object. The constructor takes ppMacro and info per
// reference, so we may look into the resulting objects later.
cmDependsFortranParser parser(this, ppDefines, info);
// Push on the starting file. // Push on the starting file.
cmDependsFortranParser_FilePush(&parser, src); cmDependsFortranParser_FilePush(&parser, src);
@ -882,10 +913,12 @@ bool cmDependsFortran::FindIncludeFile(const char* dir,
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmDependsFortranParser_s cmDependsFortranParser_s
::cmDependsFortranParser_s(cmDependsFortran* self, ::cmDependsFortranParser_s(cmDependsFortran* self,
std::set<std::string>& ppDefines,
cmDependsFortranSourceInfo& info): cmDependsFortranSourceInfo& info):
Self(self), Info(info) Self(self), PPDefinitions(ppDefines), Info(info)
{ {
this->InInterface = 0; this->InInterface = 0;
this->InPPFalseBranch = 0;
// Initialize the lexical scanner. // Initialize the lexical scanner.
cmDependsFortran_yylex_init(&this->Scanner); cmDependsFortran_yylex_init(&this->Scanner);
@ -986,6 +1019,11 @@ void cmDependsFortranParser_StringAppend(cmDependsFortranParser* parser,
void cmDependsFortranParser_SetInInterface(cmDependsFortranParser* parser, void cmDependsFortranParser_SetInInterface(cmDependsFortranParser* parser,
bool in) bool in)
{ {
if(parser->InPPFalseBranch)
{
return;
}
parser->InInterface = in; parser->InInterface = in;
} }
@ -1020,13 +1058,21 @@ void cmDependsFortranParser_Error(cmDependsFortranParser*, const char*)
void cmDependsFortranParser_RuleUse(cmDependsFortranParser* parser, void cmDependsFortranParser_RuleUse(cmDependsFortranParser* parser,
const char* name) const char* name)
{ {
parser->Info.Requires.insert(cmSystemTools::LowerCase(name) ); if(!parser->InPPFalseBranch)
{
parser->Info.Requires.insert(cmSystemTools::LowerCase(name) );
}
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmDependsFortranParser_RuleInclude(cmDependsFortranParser* parser, void cmDependsFortranParser_RuleInclude(cmDependsFortranParser* parser,
const char* name) const char* name)
{ {
if(parser->InPPFalseBranch)
{
return;
}
// If processing an include statement there must be an open file. // If processing an include statement there must be an open file.
assert(!parser->FileStack.empty()); assert(!parser->FileStack.empty());
@ -1053,48 +1099,163 @@ void cmDependsFortranParser_RuleInclude(cmDependsFortranParser* parser,
void cmDependsFortranParser_RuleModule(cmDependsFortranParser* parser, void cmDependsFortranParser_RuleModule(cmDependsFortranParser* parser,
const char* name) const char* name)
{ {
if(!parser->InInterface ) if(!parser->InPPFalseBranch && !parser->InInterface)
{ {
parser->Info.Provides.insert(cmSystemTools::LowerCase(name)); parser->Info.Provides.insert(cmSystemTools::LowerCase(name));
} }
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmDependsFortranParser_RuleDefine(cmDependsFortranParser*, const char*) void cmDependsFortranParser_RuleDefine(cmDependsFortranParser* parser,
const char* macro)
{ {
if(!parser->InPPFalseBranch)
{
parser->PPDefinitions.insert(macro);
}
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmDependsFortranParser_RuleUndef(cmDependsFortranParser*, const char*) void cmDependsFortranParser_RuleUndef(cmDependsFortranParser* parser,
const char* macro)
{ {
if(!parser->InPPFalseBranch)
{
std::set<std::string>::iterator match;
match = parser->PPDefinitions.find(macro);
if(match != parser->PPDefinitions.end())
{
parser->PPDefinitions.erase(match);
}
}
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmDependsFortranParser_RuleIfdef(cmDependsFortranParser*, const char*) void cmDependsFortranParser_RuleIfdef(cmDependsFortranParser* parser,
const char* macro)
{ {
// A new PP branch has been opened
parser->SkipToEnd.push(false);
if (parser->InPPFalseBranch)
{
parser->InPPFalseBranch++;
}
else if(parser->PPDefinitions.find(macro) == parser->PPDefinitions.end())
{
parser->InPPFalseBranch=1;
}
else
{
parser->SkipToEnd.top() = true;
}
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmDependsFortranParser_RuleIfndef(cmDependsFortranParser*, const char*) void cmDependsFortranParser_RuleIfndef(cmDependsFortranParser* parser,
const char* macro)
{ {
// A new PP branch has been opened
parser->SkipToEnd.push(false);
if (parser->InPPFalseBranch)
{
parser->InPPFalseBranch++;
}
else if(parser->PPDefinitions.find(macro) != parser->PPDefinitions.end())
{
parser->InPPFalseBranch = 1;
}
else
{
// ignore other branches
parser->SkipToEnd.top() = true;
}
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmDependsFortranParser_RuleIf(cmDependsFortranParser*) void cmDependsFortranParser_RuleIf(cmDependsFortranParser* parser)
{ {
/* Note: The current parser is _not_ able to get statements like
* #if 0
* #if 1
* #if MYSMBOL
* #if defined(MYSYMBOL)
* #if defined(MYSYMBOL) && ...
* right. The same for #elif. Thus in
* #if SYMBOL_1
* ..
* #elif SYMBOL_2
* ...
* ...
* #elif SYMBOL_N
* ..
* #else
* ..
* #endif
* _all_ N+1 branches are considered. If you got something like this
* #if defined(MYSYMBOL)
* #if !defined(MYSYMBOL)
* use
* #ifdef MYSYMBOL
* #ifndef MYSYMBOL
* instead.
*/
// A new PP branch has been opened
// Never skip! See note above.
parser->SkipToEnd.push(false);
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmDependsFortranParser_RuleElif(cmDependsFortranParser*) void cmDependsFortranParser_RuleElif(cmDependsFortranParser* parser)
{ {
/* Note: There are parser limitations. See the note at
* cmDependsFortranParser_RuleIf(..)
*/
// Allways taken unless an #ifdef or #ifndef-branch has been taken
// already. If the second condition isn't meet already
// (parser->InPPFalseBranch == 0) correct it.
if(parser->SkipToEnd.top() && !parser->InPPFalseBranch)
{
parser->InPPFalseBranch = 1;
}
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmDependsFortranParser_RuleElse(cmDependsFortranParser*) void cmDependsFortranParser_RuleElse(cmDependsFortranParser* parser)
{ {
// if the parent branch is false do nothing!
if(parser->InPPFalseBranch > 1)
{
return;
}
// parser->InPPFalseBranch is either 0 or 1. We change it denpending on
// parser->SkipToEnd.top()
if(parser->SkipToEnd.top())
{
parser->InPPFalseBranch = 1;
}
else
{
parser->InPPFalseBranch = 0;
}
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmDependsFortranParser_RuleEndif(cmDependsFortranParser*) void cmDependsFortranParser_RuleEndif(cmDependsFortranParser* parser)
{ {
if(!parser->SkipToEnd.empty())
{
parser->SkipToEnd.pop();
}
// #endif doesn't know if there was a "#else" in before, so it
// always decreases InPPFalseBranch
if(parser->InPPFalseBranch)
{
parser->InPPFalseBranch--;
}
} }

View File

@ -36,7 +36,8 @@ public:
path from the build directory to the target file, the source path from the build directory to the target file, the source
file from which to start scanning, the include file search file from which to start scanning, the include file search
path, and the target directory. */ path, and the target directory. */
cmDependsFortran(std::vector<std::string> const& includes); cmDependsFortran(std::vector<std::string> const& includes,
std::vector<std::string> const& defines);
/** Virtual destructor to cleanup subclasses properly. */ /** Virtual destructor to cleanup subclasses properly. */
virtual ~cmDependsFortran(); virtual ~cmDependsFortran();
@ -86,6 +87,7 @@ protected:
// The include file search path. // The include file search path.
std::vector<std::string> const* IncludePath; std::vector<std::string> const* IncludePath;
std::vector<std::string> PPDefinitions;
// Internal implementation details. // Internal implementation details.
cmDependsFortranInternals* Internal; cmDependsFortranInternals* Internal;

View File

@ -1485,7 +1485,13 @@ cmLocalUnixMakefileGenerator3
#ifdef CMAKE_BUILD_WITH_CMAKE #ifdef CMAKE_BUILD_WITH_CMAKE
else if(lang == "Fortran") else if(lang == "Fortran")
{ {
scanner = new cmDependsFortran(includes); std::vector<std::string> defines;
if(const char* c_defines = mf->GetDefinition("CMAKE_DEFINITIONS"))
{
cmSystemTools::ExpandListArgument(c_defines, defines);
}
scanner = new cmDependsFortran(includes, defines);
} }
else if(lang == "Java") else if(lang == "Java")
{ {
@ -1845,6 +1851,14 @@ void cmLocalUnixMakefileGenerator3
<< cid << "\")\n"; << cid << "\")\n";
} }
} }
cmakefileStream
<< "\n"
<< "# Preprocessor definitions for this directory.\n"
<< "SET(CMAKE_DEFINITIONS\n"
<< " " << this->Makefile->GetDefineFlags() << "\n"
<< " )\n";
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------

View File

@ -23,6 +23,9 @@ IF(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
in_interface/main.f90 in_interface/main.f90
in_interface/module.f90) in_interface/module.f90)
ADD_DEFINITIONS(-DFOO -DBAR=1)
ADD_EXECUTABLE(test_preprocess test_preprocess.F90)
SET(TEST_MODULE_DEPENDS 1) SET(TEST_MODULE_DEPENDS 1)
ENDIF(CMAKE_Fortran_COMPILER_SUPPORTS_F90) ENDIF(CMAKE_Fortran_COMPILER_SUPPORTS_F90)

View File

@ -0,0 +1,55 @@
MODULE Available
! no conent
END MODULE
PROGRAM PPTEST
! value of InPPFalseBranch ; values of SkipToEnd
! 0 <empty>
#ifndef FOO
! 1 ; <0>
USE NotAvailable
# ifndef FOO
! 2 ; <0,0>
USE NotAvailable
# else
! 2 ; <0,0>
USE NotAvailable
# endif
! 1 ; <0>
# ifdef FOO
! 2 ; <0,1>
USE NotAvailable
# else
! 2 ; <0,1>
USE NotAvailable
# endif
! 1 ; <0>
#else
! 0 ; <0>
USE Available
# ifndef FOO
! 1 ; <0,0>
USE NotAvailable
# else
! 0 ; <0,0>
USE Available
# endif
! 0 ; <0>
# ifdef FOO
! 0 ; <0,1>
USE Available
# else
! 1 ; <0,1>
USE NotAvailable
# endif
! 0 ; <0>
#endif
! 0 ; <empty>
#ifdef BAR
PRINT * , 'BAR was defined via ADD_DEFINITIONS'
#else
PRINT *, 'If you can read this something went wrong'
#endif
END PROGRAM