ENH: Implemented Fortran module output directory and search path flags.

This commit is contained in:
Brad King 2007-12-30 16:11:38 -05:00
parent cd8a2bbab6
commit b2e8c07af8
12 changed files with 200 additions and 26 deletions

View File

@ -0,0 +1 @@
SET(CMAKE_Fortran_MODDIR_FLAG -J)

View File

@ -12,3 +12,5 @@ SET(CMAKE_Fortran_FLAGS_DEBUG_INIT "-g")
SET(CMAKE_Fortran_FLAGS_MINSIZEREL_INIT "-xO2 -xspace -DNDEBUG") SET(CMAKE_Fortran_FLAGS_MINSIZEREL_INIT "-xO2 -xspace -DNDEBUG")
SET(CMAKE_Fortran_FLAGS_RELEASE_INIT "-xO3 -DNDEBUG") SET(CMAKE_Fortran_FLAGS_RELEASE_INIT "-xO3 -DNDEBUG")
SET(CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT "-g -xO2") SET(CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT "-g -xO2")
SET(CMAKE_Fortran_MODDIR_FLAG "-moddir=")
SET(CMAKE_Fortran_MODPATH_FLAG "-M")

View File

@ -5,3 +5,4 @@ SET(CMAKE_SHARED_LIBRARY_LINK_Fortran_FLAGS "-i_dynamic")
SET(CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG "-Wl,-rpath,") SET(CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG "-Wl,-rpath,")
SET(CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG_SEP ":") SET(CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG_SEP ":")
SET(CMAKE_SHARED_LIBRARY_SONAME_Fortran_FLAG "-Wl,-soname,") SET(CMAKE_SHARED_LIBRARY_SONAME_Fortran_FLAG "-Wl,-soname,")
SET(CMAKE_Fortran_MODDIR_FLAG "-module ")

View File

@ -194,6 +194,23 @@ bool cmDependsFortran::Finalize(std::ostream& makeDepends,
// Prepare the module search process. // Prepare the module search process.
this->LocateModules(); this->LocateModules();
// Get the directory in which stamp files will be stored.
const char* stamp_dir =
this->LocalGenerator->GetMakefile()->GetCurrentOutputDirectory();
// Get the directory in which module files will be created.
const char* mod_dir;
cmMakefile* mf = this->LocalGenerator->GetMakefile();
if(const char* target_mod_dir =
mf->GetDefinition("CMAKE_Fortran_TARGET_MODULE_DIR"))
{
mod_dir = target_mod_dir;
}
else
{
mod_dir = stamp_dir;
}
// Actually write dependencies to the streams. // Actually write dependencies to the streams.
typedef cmDependsFortranInternals::ObjectInfoMap ObjectInfoMap; typedef cmDependsFortranInternals::ObjectInfoMap ObjectInfoMap;
ObjectInfoMap const& objInfo = this->Internal->ObjectInfo; ObjectInfoMap const& objInfo = this->Internal->ObjectInfo;
@ -201,6 +218,7 @@ bool cmDependsFortran::Finalize(std::ostream& makeDepends,
i != objInfo.end(); ++i) i != objInfo.end(); ++i)
{ {
if(!this->WriteDependenciesReal(i->first.c_str(), i->second, if(!this->WriteDependenciesReal(i->first.c_str(), i->second,
mod_dir, stamp_dir,
makeDepends, internalDepends)) makeDepends, internalDepends))
{ {
return false; return false;
@ -227,16 +245,35 @@ bool cmDependsFortran::Finalize(std::ostream& makeDepends,
fcName += "/cmake_clean_Fortran.cmake"; fcName += "/cmake_clean_Fortran.cmake";
cmGeneratedFileStream fcStream(fcName.c_str()); cmGeneratedFileStream fcStream(fcName.c_str());
fcStream << "# Remove fortran modules provided by this target.\n"; fcStream << "# Remove fortran modules provided by this target.\n";
fcStream << "FILE(REMOVE\n"; fcStream << "FILE(REMOVE";
for(std::set<cmStdString>::const_iterator i = provides.begin(); for(std::set<cmStdString>::const_iterator i = provides.begin();
i != provides.end(); ++i) i != provides.end(); ++i)
{ {
std::string mod_upper = cmSystemTools::UpperCase(*i); std::string mod_upper = mod_dir;
std::string mod_lower = *i; mod_upper += "/";
fcStream << " \"" << mod_lower << ".mod\"" mod_upper += cmSystemTools::UpperCase(*i);
<< " \"" << mod_lower << ".mod.stamp\"" mod_upper += ".mod";
<< " \"" << mod_upper << ".mod\"" std::string mod_lower = mod_dir;
<< " \"" << mod_upper << ".mod.stamp\"\n"; mod_lower += "/";
mod_lower += *i;
mod_lower += ".mod";
std::string stamp = stamp_dir;
stamp += "/";
stamp += *i;
stamp += ".mod.stamp";
fcStream << "\n";
fcStream << " \"" <<
this->LocalGenerator->Convert(mod_lower.c_str(),
cmLocalGenerator::START_OUTPUT)
<< "\"\n";
fcStream << " \"" <<
this->LocalGenerator->Convert(mod_upper.c_str(),
cmLocalGenerator::START_OUTPUT)
<< "\"\n";
fcStream << " \"" <<
this->LocalGenerator->Convert(stamp.c_str(),
cmLocalGenerator::START_OUTPUT)
<< "\"\n";
} }
fcStream << " )\n"; fcStream << " )\n";
} }
@ -304,19 +341,19 @@ void cmDependsFortran::LocateModules()
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmDependsFortran::MatchLocalModules() void cmDependsFortran::MatchLocalModules()
{ {
const char* moduleDir = const char* stampDir =
this->LocalGenerator->GetMakefile()->GetCurrentOutputDirectory(); this->LocalGenerator->GetMakefile()->GetCurrentOutputDirectory();
std::set<cmStdString> const& provides = this->Internal->TargetProvides; std::set<cmStdString> const& provides = this->Internal->TargetProvides;
for(std::set<cmStdString>::const_iterator i = provides.begin(); for(std::set<cmStdString>::const_iterator i = provides.begin();
i != provides.end(); ++i) i != provides.end(); ++i)
{ {
this->ConsiderModule(i->c_str(), moduleDir); this->ConsiderModule(i->c_str(), stampDir);
} }
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmDependsFortran::MatchRemoteModules(std::istream& fin, void cmDependsFortran::MatchRemoteModules(std::istream& fin,
const char* moduleDir) const char* stampDir)
{ {
std::string line; std::string line;
bool doing_provides = false; bool doing_provides = false;
@ -332,7 +369,7 @@ void cmDependsFortran::MatchRemoteModules(std::istream& fin,
{ {
if(doing_provides) if(doing_provides)
{ {
this->ConsiderModule(line.c_str()+1, moduleDir); this->ConsiderModule(line.c_str()+1, stampDir);
} }
} }
else if(line == "provides") else if(line == "provides")
@ -348,7 +385,7 @@ void cmDependsFortran::MatchRemoteModules(std::istream& fin,
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmDependsFortran::ConsiderModule(const char* name, void cmDependsFortran::ConsiderModule(const char* name,
const char* moduleDir) const char* stampDir)
{ {
// Locate each required module. // Locate each required module.
typedef cmDependsFortranInternals::TargetRequiresMap TargetRequiresMap; typedef cmDependsFortranInternals::TargetRequiresMap TargetRequiresMap;
@ -358,7 +395,7 @@ void cmDependsFortran::ConsiderModule(const char* name,
required->second.empty()) required->second.empty())
{ {
// The module is provided by a CMake target. It will have a stamp file. // The module is provided by a CMake target. It will have a stamp file.
std::string stampFile = moduleDir; std::string stampFile = stampDir;
stampFile += "/"; stampFile += "/";
stampFile += name; stampFile += name;
stampFile += ".mod.stamp"; stampFile += ".mod.stamp";
@ -371,6 +408,7 @@ bool
cmDependsFortran cmDependsFortran
::WriteDependenciesReal(const char *obj, ::WriteDependenciesReal(const char *obj,
cmDependsFortranSourceInfo const& info, cmDependsFortranSourceInfo const& info,
const char* mod_dir, const char* stamp_dir,
std::ostream& makeDepends, std::ostream& makeDepends,
std::ostream& internalDepends) std::ostream& internalDepends)
{ {
@ -379,10 +417,6 @@ cmDependsFortran
// Get the source file for this object. // Get the source file for this object.
const char* src = info.Source.c_str(); const char* src = info.Source.c_str();
// Get the directory in which stamp files will be stored.
std::string mod_dir =
this->LocalGenerator->GetMakefile()->GetCurrentOutputDirectory();
// Write the include dependencies to the output stream. // Write the include dependencies to the output stream.
internalDepends << obj << std::endl; internalDepends << obj << std::endl;
internalDepends << " " << src << std::endl; internalDepends << " " << src << std::endl;
@ -414,7 +448,7 @@ cmDependsFortran
// The module is provided by a different source in the same // The module is provided by a different source in the same
// target. Add the proxy dependency to make sure the other // target. Add the proxy dependency to make sure the other
// source builds first. // source builds first.
std::string proxy = mod_dir; std::string proxy = stamp_dir;
proxy += "/"; proxy += "/";
proxy += *i; proxy += *i;
proxy += ".mod.proxy"; proxy += ".mod.proxy";
@ -460,7 +494,7 @@ cmDependsFortran
for(std::set<cmStdString>::const_iterator i = info.Provides.begin(); for(std::set<cmStdString>::const_iterator i = info.Provides.begin();
i != info.Provides.end(); ++i) i != info.Provides.end(); ++i)
{ {
std::string proxy = mod_dir; std::string proxy = stamp_dir;
proxy += "/"; proxy += "/";
proxy += *i; proxy += *i;
proxy += ".mod.proxy"; proxy += ".mod.proxy";
@ -493,7 +527,7 @@ cmDependsFortran
this->LocalGenerator->Convert(modFile.c_str(), this->LocalGenerator->Convert(modFile.c_str(),
cmLocalGenerator::HOME_OUTPUT, cmLocalGenerator::HOME_OUTPUT,
cmLocalGenerator::SHELL); cmLocalGenerator::SHELL);
std::string stampFile = mod_dir; std::string stampFile = stamp_dir;
stampFile += "/"; stampFile += "/";
stampFile += m; stampFile += m;
stampFile += ".mod.stamp"; stampFile += ".mod.stamp";

View File

@ -60,8 +60,8 @@ protected:
// Find all the modules required by the target. // Find all the modules required by the target.
void LocateModules(); void LocateModules();
void MatchLocalModules(); void MatchLocalModules();
void MatchRemoteModules(std::istream& fin, const char* moduleDir); void MatchRemoteModules(std::istream& fin, const char* stampDir);
void ConsiderModule(const char* name, const char* moduleDir); void ConsiderModule(const char* name, const char* stampDir);
bool FindModule(std::string const& name, std::string& module); bool FindModule(std::string const& name, std::string& module);
// Implement writing/checking methods required by superclass. // Implement writing/checking methods required by superclass.
@ -72,6 +72,7 @@ protected:
// Actually write the depenencies to the streams. // Actually write the depenencies to the streams.
bool WriteDependenciesReal(const char *obj, bool WriteDependenciesReal(const char *obj,
cmDependsFortranSourceInfo const& info, cmDependsFortranSourceInfo const& info,
const char* mod_dir, const char* stamp_dir,
std::ostream& makeDepends, std::ostream& makeDepends,
std::ostream& internalDepends); std::ostream& internalDepends);

View File

@ -679,6 +679,15 @@ void cmDocumentVariables::DefineVariables(cmake* cm)
false, false,
"Variables that Control the Build"); "Variables that Control the Build");
cm->DefineProperty
("CMAKE_Fortran_MODULE_DIRECTORY", cmProperty::VARIABLE,
"Fortran module output directory.",
"This variable is used to initialize the "
"Fortran_MODULE_DIRECTORY property on all the targets. "
"See that target property for additional information.",
false,
"Variables that Control the Build");
cm->DefineProperty cm->DefineProperty
("CMAKE_LIBRARY_OUTPUT_DIRECTORY", cmProperty::VARIABLE, ("CMAKE_LIBRARY_OUTPUT_DIRECTORY", cmProperty::VARIABLE,
"Where to put all the LIBRARY targets when built.", "Where to put all the LIBRARY targets when built.",

View File

@ -36,6 +36,7 @@ cmMakefileTargetGenerator::cmMakefileTargetGenerator()
this->InfoFileStream = 0; this->InfoFileStream = 0;
this->FlagFileStream = 0; this->FlagFileStream = 0;
this->CustomCommandDriver = OnBuild; this->CustomCommandDriver = OnBuild;
this->FortranModuleDirectoryComputed = false;
} }
cmMakefileTargetGenerator * cmMakefileTargetGenerator *
@ -268,6 +269,12 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
->AddLanguageFlags(flags, lang, ->AddLanguageFlags(flags, lang,
this->LocalGenerator->ConfigurationName.c_str()); this->LocalGenerator->ConfigurationName.c_str());
// Fortran-specific flags computed for this target.
if(*l == "Fortran")
{
this->AddFortranFlags(flags);
}
// Add shared-library flags if needed. // Add shared-library flags if needed.
this->LocalGenerator->AddSharedFlags(flags, lang, shared); this->LocalGenerator->AddSharedFlags(flags, lang, shared);
@ -823,6 +830,15 @@ void cmMakefileTargetGenerator::WriteTargetDependRules()
<< " )\n"; << " )\n";
} }
// Check for a target-specific module output directory.
if(const char* mdir = this->GetFortranModuleDirectory())
{
*this->InfoFileStream
<< "\n"
<< "# Fortran module output directory.\n"
<< "SET(CMAKE_Fortran_TARGET_MODULE_DIR \"" << mdir << "\")\n";
}
// and now write the rule to use it // and now write the rule to use it
std::vector<std::string> depends; std::vector<std::string> depends;
std::vector<std::string> commands; std::vector<std::string> commands;
@ -1423,3 +1439,82 @@ cmMakefileTargetGenerator
link_command += " --verbose=$(VERBOSE)"; link_command += " --verbose=$(VERBOSE)";
makefile_commands.push_back(link_command); makefile_commands.push_back(link_command);
} }
//----------------------------------------------------------------------------
const char* cmMakefileTargetGenerator::GetFortranModuleDirectory()
{
// Compute the module directory.
if(!this->FortranModuleDirectoryComputed)
{
const char* target_mod_dir =
this->Target->GetProperty("Fortran_MODULE_DIRECTORY");
const char* moddir_flag =
this->Makefile->GetDefinition("CMAKE_Fortran_MODDIR_FLAG");
if(target_mod_dir && moddir_flag)
{
// Compute the full path to the module directory.
if(cmSystemTools::FileIsFullPath(target_mod_dir))
{
// Already a full path.
this->FortranModuleDirectory = target_mod_dir;
}
else
{
// Interpret relative to the current output directory.
this->FortranModuleDirectory =
this->Makefile->GetCurrentOutputDirectory();
this->FortranModuleDirectory += "/";
this->FortranModuleDirectory += target_mod_dir;
}
// Make sure the module output directory exists.
cmSystemTools::MakeDirectory(this->FortranModuleDirectory.c_str());
}
this->FortranModuleDirectoryComputed = true;
}
// Return the computed directory.
if(this->FortranModuleDirectory.empty())
{
return 0;
}
else
{
return this->FortranModuleDirectory.c_str();
}
}
//----------------------------------------------------------------------------
void cmMakefileTargetGenerator::AddFortranFlags(std::string& flags)
{
// Add a module output directory flag if necessary.
if(const char* mod_dir = this->GetFortranModuleDirectory())
{
const char* moddir_flag =
this->Makefile->GetRequiredDefinition("CMAKE_Fortran_MODDIR_FLAG");
std::string modflag = moddir_flag;
modflag += this->Convert(mod_dir,
cmLocalGenerator::START_OUTPUT,
cmLocalGenerator::SHELL);
this->LocalGenerator->AppendFlags(flags, modflag.c_str());
}
// If there is a separate module path flag then duplicate the
// include path with it. This compiler does not search the include
// path for modules.
if(const char* modpath_flag =
this->Makefile->GetDefinition("CMAKE_Fortran_MODPATH_FLAG"))
{
std::vector<std::string> includes;
this->LocalGenerator->GetIncludeDirectories(includes);
for(std::vector<std::string>::const_iterator idi = includes.begin();
idi != includes.end(); ++idi)
{
std::string flg = modpath_flag;
flg += this->Convert(idi->c_str(),
cmLocalGenerator::NONE,
cmLocalGenerator::SHELL);
this->LocalGenerator->AppendFlags(flags, flg.c_str());
}
}
}

View File

@ -184,6 +184,14 @@ protected:
typedef std::map<cmStdString, cmStdString> MultipleOutputPairsType; typedef std::map<cmStdString, cmStdString> MultipleOutputPairsType;
MultipleOutputPairsType MultipleOutputPairs; MultipleOutputPairsType MultipleOutputPairs;
// Target-wide Fortran module output directory.
bool FortranModuleDirectoryComputed;
std::string FortranModuleDirectory;
const char* GetFortranModuleDirectory();
// Compute target-specific Fortran language flags.
void AddFortranFlags(std::string& flags);
//================================================================== //==================================================================
// Convenience routines that do nothing more than forward to // Convenience routines that do nothing more than forward to
// implementaitons // implementaitons

View File

@ -284,6 +284,15 @@ void cmTarget::DefineProperties(cmake *cm)
"exported symbols and then used for linking. " "exported symbols and then used for linking. "
"All Windows-based systems including Cygwin are DLL platforms."); "All Windows-based systems including Cygwin are DLL platforms.");
cm->DefineProperty
("Fortran_MODULE_DIRECTORY", cmProperty::TARGET,
"Specify output directory for Fortran modules provided by the target.",
"If the target contains Fortran source files that provide modules "
"and the compiler supports a module output directory this specifies "
"the directory in which the modules will be placed. "
"When this property is not set the modules will be placed in the "
"build directory corresponding to the target's source directory.");
cm->DefineProperty cm->DefineProperty
("XCODE_ATTRIBUTE_<an-attribute>", cmProperty::TARGET, ("XCODE_ATTRIBUTE_<an-attribute>", cmProperty::TARGET,
"Set Xcode target attributes directly.", "Set Xcode target attributes directly.",
@ -403,6 +412,7 @@ void cmTarget::SetMakefile(cmMakefile* mf)
this->SetPropertyDefault("ARCHIVE_OUTPUT_DIRECTORY", 0); this->SetPropertyDefault("ARCHIVE_OUTPUT_DIRECTORY", 0);
this->SetPropertyDefault("LIBRARY_OUTPUT_DIRECTORY", 0); this->SetPropertyDefault("LIBRARY_OUTPUT_DIRECTORY", 0);
this->SetPropertyDefault("RUNTIME_OUTPUT_DIRECTORY", 0); this->SetPropertyDefault("RUNTIME_OUTPUT_DIRECTORY", 0);
this->SetPropertyDefault("Fortran_MODULE_DIRECTORY", 0);
// Collect the set of configuration types. // Collect the set of configuration types.
std::vector<std::string> configNames; std::vector<std::string> configNames;

View File

@ -23,9 +23,7 @@ IF(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
in_interface/main.f90 in_interface/main.f90
in_interface/module.f90) in_interface/module.f90)
IF(CMAKE_Fortran_COMPILER_ID MATCHES GNU) SET(TEST_MODULE_DEPENDS 1)
SET(TEST_MODULE_DEPENDS 1)
ENDIF(CMAKE_Fortran_COMPILER_ID MATCHES GNU)
ENDIF(CMAKE_Fortran_COMPILER_SUPPORTS_F90) ENDIF(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
IF(TEST_MODULE_DEPENDS) IF(TEST_MODULE_DEPENDS)
@ -57,6 +55,13 @@ IF(TEST_MODULE_DEPENDS)
) )
ADD_CUSTOM_TARGET(ExternalTarget ALL DEPENDS ${testf_BINARY_DIR}/ExternalProject) ADD_CUSTOM_TARGET(ExternalTarget ALL DEPENDS ${testf_BINARY_DIR}/ExternalProject)
# Test module output directory if available.
IF(CMAKE_Fortran_MODDIR_FLAG)
SET(Library_MODDIR "${testf_BINARY_DIR}/Library/modules")
ELSE(CMAKE_Fortran_MODDIR_FLAG)
SET(Library_MODDIR "${testf_BINARY_DIR}/Library")
ENDIF(CMAKE_Fortran_MODDIR_FLAG)
ADD_SUBDIRECTORY(Library) ADD_SUBDIRECTORY(Library)
ADD_SUBDIRECTORY(Executable) ADD_SUBDIRECTORY(Executable)
ENDIF(TEST_MODULE_DEPENDS) ENDIF(TEST_MODULE_DEPENDS)

View File

@ -1,4 +1,4 @@
include_directories(${testf_BINARY_DIR}/Library) include_directories(${Library_MODDIR})
include_directories(${testf_BINARY_DIR}/External) include_directories(${testf_BINARY_DIR}/External)
link_directories(${testf_BINARY_DIR}/External) link_directories(${testf_BINARY_DIR}/External)

View File

@ -1,3 +1,11 @@
INCLUDE_DIRECTORIES(${Library_MODDIR})
ADD_LIBRARY(subdir_mods a.f90 b.f90) ADD_LIBRARY(subdir_mods a.f90 b.f90)
ADD_EXECUTABLE(subdir_exe main.f90) ADD_EXECUTABLE(subdir_exe main.f90)
TARGET_LINK_LIBRARIES(subdir_exe subdir_mods) TARGET_LINK_LIBRARIES(subdir_exe subdir_mods)
# Test module output directory if available.
IF(CMAKE_Fortran_MODDIR_FLAG)
SET_TARGET_PROPERTIES(subdir_mods PROPERTIES
Fortran_MODULE_DIRECTORY modules
)
ENDIF(CMAKE_Fortran_MODDIR_FLAG)