Introduce "generator expressions" to add_test()
[cmake.git] / Source / cmGlobalVisualStudioGenerator.cxx
blob1652d172cc353df54ab53e187e54397c538847b9
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmGlobalVisualStudioGenerator.cxx,v $
5 Language: C++
6 Date: $Date: 2009-07-14 18:16:46 $
7 Version: $Revision: 1.16 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmGlobalVisualStudioGenerator.h"
19 #include "cmCallVisualStudioMacro.h"
20 #include "cmLocalGenerator.h"
21 #include "cmMakefile.h"
22 #include "cmTarget.h"
24 //----------------------------------------------------------------------------
25 cmGlobalVisualStudioGenerator::cmGlobalVisualStudioGenerator()
29 //----------------------------------------------------------------------------
30 cmGlobalVisualStudioGenerator::~cmGlobalVisualStudioGenerator()
34 //----------------------------------------------------------------------------
35 void cmGlobalVisualStudioGenerator::Generate()
37 // Add a special target that depends on ALL projects for easy build
38 // of one configuration only.
39 const char* no_working_dir = 0;
40 std::vector<std::string> no_depends;
41 cmCustomCommandLines no_commands;
42 std::map<cmStdString, std::vector<cmLocalGenerator*> >::iterator it;
43 for(it = this->ProjectMap.begin(); it!= this->ProjectMap.end(); ++it)
45 std::vector<cmLocalGenerator*>& gen = it->second;
46 // add the ALL_BUILD to the first local generator of each project
47 if(gen.size())
49 // Use no actual command lines so that the target itself is not
50 // considered always out of date.
51 cmTarget* allBuild =
52 gen[0]->GetMakefile()->
53 AddUtilityCommand("ALL_BUILD", true, no_working_dir,
54 no_depends, no_commands, false,
55 "Build all projects");
56 // Now make all targets depend on the ALL_BUILD target
57 cmTargets targets;
58 for(std::vector<cmLocalGenerator*>::iterator i = gen.begin();
59 i != gen.end(); ++i)
61 cmTargets& targets = (*i)->GetMakefile()->GetTargets();
62 for(cmTargets::iterator t = targets.begin();
63 t != targets.end(); ++t)
65 if(!this->IsExcluded(gen[0], t->second))
67 allBuild->AddUtility(t->second.GetName());
74 // Fix utility dependencies to avoid linking to libraries.
75 this->FixUtilityDepends();
77 // Configure CMake Visual Studio macros, for this user on this version
78 // of Visual Studio.
79 this->ConfigureCMakeVisualStudioMacros();
81 // Run all the local generators.
82 this->cmGlobalGenerator::Generate();
85 //----------------------------------------------------------------------------
86 bool IsVisualStudioMacrosFileRegistered(const std::string& macrosFile,
87 const std::string& regKeyBase,
88 std::string& nextAvailableSubKeyName);
90 void RegisterVisualStudioMacros(const std::string& macrosFile,
91 const std::string& regKeyBase);
93 //----------------------------------------------------------------------------
94 #define CMAKE_VSMACROS_FILENAME \
95 "CMakeVSMacros2.vsmacros"
97 #define CMAKE_VSMACROS_RELOAD_MACRONAME \
98 "Macros.CMakeVSMacros2.Macros.ReloadProjects"
100 #define CMAKE_VSMACROS_STOP_MACRONAME \
101 "Macros.CMakeVSMacros2.Macros.StopBuild"
103 //----------------------------------------------------------------------------
104 void cmGlobalVisualStudioGenerator::ConfigureCMakeVisualStudioMacros()
106 cmMakefile* mf = this->LocalGenerators[0]->GetMakefile();
107 std::string dir = this->GetUserMacrosDirectory();
109 if (mf != 0 && dir != "")
111 std::string src = mf->GetRequiredDefinition("CMAKE_ROOT");
112 src += "/Templates/" CMAKE_VSMACROS_FILENAME;
114 std::string dst = dir + "/CMakeMacros/" CMAKE_VSMACROS_FILENAME;
116 // Copy the macros file to the user directory only if the
117 // destination does not exist or the source location is newer.
118 // This will allow the user to edit the macros for development
119 // purposes but newer versions distributed with CMake will replace
120 // older versions in user directories.
121 int res;
122 if(!cmSystemTools::FileTimeCompare(src.c_str(), dst.c_str(), &res) ||
123 res > 0)
125 if (!cmSystemTools::CopyFileAlways(src.c_str(), dst.c_str()))
127 std::ostringstream oss;
128 oss << "Could not copy from: " << src << std::endl;
129 oss << " to: " << dst << std::endl;
130 cmSystemTools::Message(oss.str().c_str(), "Warning");
134 RegisterVisualStudioMacros(dst, this->GetUserMacrosRegKeyBase());
138 //----------------------------------------------------------------------------
139 void
140 cmGlobalVisualStudioGenerator
141 ::CallVisualStudioMacro(MacroName m,
142 const char* vsSolutionFile)
144 // If any solution or project files changed during the generation,
145 // tell Visual Studio to reload them...
146 cmMakefile* mf = this->LocalGenerators[0]->GetMakefile();
147 std::string dir = this->GetUserMacrosDirectory();
149 // Only really try to call the macro if:
150 // - mf is non-NULL
151 // - there is a UserMacrosDirectory
152 // - the CMake vsmacros file exists
153 // - the CMake vsmacros file is registered
154 // - there were .sln/.vcproj files changed during generation
156 if (mf != 0 && dir != "")
158 std::string macrosFile = dir + "/CMakeMacros/" CMAKE_VSMACROS_FILENAME;
159 std::string nextSubkeyName;
160 if (cmSystemTools::FileExists(macrosFile.c_str()) &&
161 IsVisualStudioMacrosFileRegistered(macrosFile,
162 this->GetUserMacrosRegKeyBase(), nextSubkeyName)
165 std::string topLevelSlnName;
166 if(vsSolutionFile)
168 topLevelSlnName = vsSolutionFile;
170 else
172 topLevelSlnName = mf->GetStartOutputDirectory();
173 topLevelSlnName += "/";
174 topLevelSlnName += mf->GetProjectName();
175 topLevelSlnName += ".sln";
178 if(m == MacroReload)
180 std::vector<std::string> filenames;
181 this->GetFilesReplacedDuringGenerate(filenames);
182 if (filenames.size() > 0)
184 // Convert vector to semi-colon delimited string of filenames:
185 std::string projects;
186 std::vector<std::string>::iterator it = filenames.begin();
187 if (it != filenames.end())
189 projects = *it;
190 ++it;
192 for (; it != filenames.end(); ++it)
194 projects += ";";
195 projects += *it;
197 cmCallVisualStudioMacro::CallMacro(topLevelSlnName,
198 CMAKE_VSMACROS_RELOAD_MACRONAME, projects,
199 this->GetCMakeInstance()->GetDebugOutput());
202 else if(m == MacroStop)
204 cmCallVisualStudioMacro::CallMacro(topLevelSlnName,
205 CMAKE_VSMACROS_STOP_MACRONAME, "",
206 this->GetCMakeInstance()->GetDebugOutput());
212 //----------------------------------------------------------------------------
213 std::string cmGlobalVisualStudioGenerator::GetUserMacrosDirectory()
215 return "";
218 //----------------------------------------------------------------------------
219 std::string cmGlobalVisualStudioGenerator::GetUserMacrosRegKeyBase()
221 return "";
224 //----------------------------------------------------------------------------
225 void cmGlobalVisualStudioGenerator::FixUtilityDepends()
227 // Skip for VS versions 8 and above.
228 if(!this->VSLinksDependencies())
230 return;
233 // For VS versions before 8:
235 // When a target that links contains a project-level dependency on a
236 // library target that library is automatically linked. In order to
237 // allow utility-style project-level dependencies that do not
238 // actually link we need to automatically insert an intermediate
239 // custom target.
241 // Here we edit the utility dependencies of a target to add the
242 // intermediate custom target when necessary.
243 for(unsigned i = 0; i < this->LocalGenerators.size(); ++i)
245 cmTargets* targets =
246 &(this->LocalGenerators[i]->GetMakefile()->GetTargets());
247 for(cmTargets::iterator tarIt = targets->begin();
248 tarIt != targets->end(); ++tarIt)
250 this->FixUtilityDependsForTarget(tarIt->second);
255 //----------------------------------------------------------------------------
256 void
257 cmGlobalVisualStudioGenerator::FixUtilityDependsForTarget(cmTarget& target)
259 // Only targets that link need to be fixed.
260 if(target.GetType() != cmTarget::STATIC_LIBRARY &&
261 target.GetType() != cmTarget::SHARED_LIBRARY &&
262 target.GetType() != cmTarget::MODULE_LIBRARY &&
263 target.GetType() != cmTarget::EXECUTABLE)
265 return;
268 #if 0
269 // This feature makes a mess in SLN files for VS 7.1 and below. It
270 // creates an extra target for every target that is "linked" by a
271 // static library. Without this feature static libraries do not
272 // wait until their "link" dependencies are built to build. This is
273 // not a problem 99.9% of the time, and projects that do have the
274 // problem can enable this work-around by using add_dependencies.
276 // Static libraries cannot depend directly on the targets to which
277 // they link because VS will copy those targets into the library
278 // (for VS < 8). To work around the problem we copy the
279 // dependencies to be utility dependencies so that the work-around
280 // below is used.
281 if(target.GetType() == cmTarget::STATIC_LIBRARY)
283 cmTarget::LinkLibraryVectorType const& libs = target.GetLinkLibraries();
284 for(cmTarget::LinkLibraryVectorType::const_iterator i = libs.begin();
285 i != libs.end(); ++i)
287 if(cmTarget* depTarget = this->FindTarget(0, i->first.c_str(), false))
289 target.AddUtility(depTarget->GetName());
293 #endif
295 // Look at each utility dependency.
296 for(std::set<cmStdString>::const_iterator ui =
297 target.GetUtilities().begin();
298 ui != target.GetUtilities().end(); ++ui)
300 if(cmTarget* depTarget = this->FindTarget(0, ui->c_str()))
302 if(depTarget->GetType() == cmTarget::STATIC_LIBRARY ||
303 depTarget->GetType() == cmTarget::SHARED_LIBRARY ||
304 depTarget->GetType() == cmTarget::MODULE_LIBRARY)
306 // This utility dependency will cause an attempt to link. If
307 // the depender does not already link the dependee we need an
308 // intermediate target.
309 if(!this->CheckTargetLinks(target, ui->c_str()))
311 this->CreateUtilityDependTarget(*depTarget);
318 //----------------------------------------------------------------------------
319 void
320 cmGlobalVisualStudioGenerator::CreateUtilityDependTarget(cmTarget& target)
322 // This target is a library on which a utility dependency exists.
323 // We need to create an intermediate custom target to hook up the
324 // dependency without causing a link.
325 const char* altName = target.GetProperty("ALTERNATIVE_DEPENDENCY_NAME");
326 if(!altName)
328 // Create the intermediate utility target.
329 std::string altNameStr = target.GetName();
330 altNameStr += "_UTILITY";
331 const std::vector<std::string> no_depends;
332 cmCustomCommandLines no_commands;
333 const char* no_working_dir = 0;
334 const char* no_comment = 0;
335 target.GetMakefile()->AddUtilityCommand(altNameStr.c_str(), true,
336 no_working_dir, no_depends,
337 no_commands, false, no_comment);
338 target.SetProperty("ALTERNATIVE_DEPENDENCY_NAME", altNameStr.c_str());
340 // Most targets have a GUID created in ConfigureFinalPass. Since
341 // that has already been called, create one for this target now.
342 this->CreateGUID(altNameStr.c_str());
344 // The intermediate target should depend on the original target.
345 if(cmTarget* alt = this->FindTarget(0, altNameStr.c_str()))
347 alt->AddUtility(target.GetName());
352 //----------------------------------------------------------------------------
353 bool cmGlobalVisualStudioGenerator::CheckTargetLinks(cmTarget& target,
354 const char* name)
356 // Return whether the given target links to a target with the given name.
357 if(target.GetType() == cmTarget::STATIC_LIBRARY)
359 // Static libraries never link to anything.
360 return false;
362 cmTarget::LinkLibraryVectorType const& libs = target.GetLinkLibraries();
363 for(cmTarget::LinkLibraryVectorType::const_iterator i = libs.begin();
364 i != libs.end(); ++i)
366 if(i->first == name)
368 return true;
371 return false;
374 //----------------------------------------------------------------------------
375 const char*
376 cmGlobalVisualStudioGenerator::GetUtilityForTarget(cmTarget& target,
377 const char* name)
379 // Possibly depend on an intermediate utility target to avoid
380 // linking.
381 if(target.GetType() == cmTarget::STATIC_LIBRARY ||
382 target.GetType() == cmTarget::SHARED_LIBRARY ||
383 target.GetType() == cmTarget::MODULE_LIBRARY ||
384 target.GetType() == cmTarget::EXECUTABLE)
386 // The depender is a target that links. Lookup the dependee to
387 // see if it provides an alternative dependency name.
388 if(cmTarget* depTarget = this->FindTarget(0, name))
390 // Check for an alternative name created by FixUtilityDepends.
391 if(const char* altName =
392 depTarget->GetProperty("ALTERNATIVE_DEPENDENCY_NAME"))
394 // The alternative name is needed only if the depender does
395 // not really link to the dependee.
396 if(!this->CheckTargetLinks(target, name))
398 return altName;
404 // No special case. Just use the original dependency name.
405 return name;
408 //----------------------------------------------------------------------------
409 #include <windows.h>
411 //----------------------------------------------------------------------------
412 bool IsVisualStudioMacrosFileRegistered(const std::string& macrosFile,
413 const std::string& regKeyBase,
414 std::string& nextAvailableSubKeyName)
416 bool macrosRegistered = false;
418 std::string s1;
419 std::string s2;
421 // Make lowercase local copies, convert to Unix slashes, and
422 // see if the resulting strings are the same:
423 s1 = cmSystemTools::LowerCase(macrosFile);
424 cmSystemTools::ConvertToUnixSlashes(s1);
426 std::string keyname;
427 HKEY hkey = NULL;
428 LONG result = ERROR_SUCCESS;
429 DWORD index = 0;
431 keyname = regKeyBase + "\\OtherProjects7";
432 hkey = NULL;
433 result = RegOpenKeyEx(HKEY_CURRENT_USER, keyname.c_str(),
434 0, KEY_READ, &hkey);
435 if (ERROR_SUCCESS == result)
437 // Iterate the subkeys and look for the values of interest in each subkey:
438 CHAR subkeyname[256];
439 DWORD cch_subkeyname = sizeof(subkeyname)/sizeof(subkeyname[0]);
440 CHAR keyclass[256];
441 DWORD cch_keyclass = sizeof(keyclass)/sizeof(keyclass[0]);
442 FILETIME lastWriteTime;
443 lastWriteTime.dwHighDateTime = 0;
444 lastWriteTime.dwLowDateTime = 0;
446 while (ERROR_SUCCESS == RegEnumKeyEx(hkey, index, subkeyname,
447 &cch_subkeyname,
448 0, keyclass, &cch_keyclass, &lastWriteTime))
450 // Open the subkey and query the values of interest:
451 HKEY hsubkey = NULL;
452 result = RegOpenKeyEx(hkey, subkeyname, 0, KEY_READ, &hsubkey);
453 if (ERROR_SUCCESS == result)
455 DWORD valueType = REG_SZ;
456 CHAR data1[256];
457 DWORD cch_data1 = sizeof(data1)/sizeof(data1[0]);
458 RegQueryValueEx(hsubkey, "Path", 0, &valueType,
459 (LPBYTE) &data1[0], &cch_data1);
461 DWORD data2 = 0;
462 DWORD cch_data2 = sizeof(data2);
463 RegQueryValueEx(hsubkey, "Security", 0, &valueType,
464 (LPBYTE) &data2, &cch_data2);
466 DWORD data3 = 0;
467 DWORD cch_data3 = sizeof(data3);
468 RegQueryValueEx(hsubkey, "StorageFormat", 0, &valueType,
469 (LPBYTE) &data3, &cch_data3);
471 s2 = cmSystemTools::LowerCase(data1);
472 cmSystemTools::ConvertToUnixSlashes(s2);
473 if (s2 == s1)
475 macrosRegistered = true;
478 std::string fullname(data1);
479 std::string filename;
480 std::string filepath;
481 std::string filepathname;
482 std::string filepathpath;
483 if (cmSystemTools::FileExists(fullname.c_str()))
485 filename = cmSystemTools::GetFilenameName(fullname);
486 filepath = cmSystemTools::GetFilenamePath(fullname);
487 filepathname = cmSystemTools::GetFilenameName(filepath);
488 filepathpath = cmSystemTools::GetFilenamePath(filepath);
491 //std::cout << keyname << "\\" << subkeyname << ":" << std::endl;
492 //std::cout << " Path: " << data1 << std::endl;
493 //std::cout << " Security: " << data2 << std::endl;
494 //std::cout << " StorageFormat: " << data3 << std::endl;
495 //std::cout << " filename: " << filename << std::endl;
496 //std::cout << " filepath: " << filepath << std::endl;
497 //std::cout << " filepathname: " << filepathname << std::endl;
498 //std::cout << " filepathpath: " << filepathpath << std::endl;
499 //std::cout << std::endl;
501 RegCloseKey(hsubkey);
503 else
505 std::cout << "error opening subkey: " << subkeyname << std::endl;
506 std::cout << std::endl;
509 ++index;
510 cch_subkeyname = sizeof(subkeyname)/sizeof(subkeyname[0]);
511 cch_keyclass = sizeof(keyclass)/sizeof(keyclass[0]);
512 lastWriteTime.dwHighDateTime = 0;
513 lastWriteTime.dwLowDateTime = 0;
516 RegCloseKey(hkey);
518 else
520 std::cout << "error opening key: " << keyname << std::endl;
521 std::cout << std::endl;
525 // Pass back next available sub key name, assuming sub keys always
526 // follow the expected naming scheme. Expected naming scheme is that
527 // the subkeys of OtherProjects7 is 0 to n-1, so it's ok to use "n"
528 // as the name of the next subkey.
529 std::ostringstream ossNext;
530 ossNext << index;
531 nextAvailableSubKeyName = ossNext.str();
534 keyname = regKeyBase + "\\RecordingProject7";
535 hkey = NULL;
536 result = RegOpenKeyEx(HKEY_CURRENT_USER, keyname.c_str(),
537 0, KEY_READ, &hkey);
538 if (ERROR_SUCCESS == result)
540 DWORD valueType = REG_SZ;
541 CHAR data1[256];
542 DWORD cch_data1 = sizeof(data1)/sizeof(data1[0]);
543 RegQueryValueEx(hkey, "Path", 0, &valueType,
544 (LPBYTE) &data1[0], &cch_data1);
546 DWORD data2 = 0;
547 DWORD cch_data2 = sizeof(data2);
548 RegQueryValueEx(hkey, "Security", 0, &valueType,
549 (LPBYTE) &data2, &cch_data2);
551 DWORD data3 = 0;
552 DWORD cch_data3 = sizeof(data3);
553 RegQueryValueEx(hkey, "StorageFormat", 0, &valueType,
554 (LPBYTE) &data3, &cch_data3);
556 s2 = cmSystemTools::LowerCase(data1);
557 cmSystemTools::ConvertToUnixSlashes(s2);
558 if (s2 == s1)
560 macrosRegistered = true;
563 //std::cout << keyname << ":" << std::endl;
564 //std::cout << " Path: " << data1 << std::endl;
565 //std::cout << " Security: " << data2 << std::endl;
566 //std::cout << " StorageFormat: " << data3 << std::endl;
567 //std::cout << std::endl;
569 RegCloseKey(hkey);
571 else
573 std::cout << "error opening key: " << keyname << std::endl;
574 std::cout << std::endl;
577 return macrosRegistered;
580 //----------------------------------------------------------------------------
581 void WriteVSMacrosFileRegistryEntry(
582 const std::string& nextAvailableSubKeyName,
583 const std::string& macrosFile,
584 const std::string& regKeyBase)
586 std::string keyname = regKeyBase + "\\OtherProjects7";
587 HKEY hkey = NULL;
588 LONG result = RegOpenKeyEx(HKEY_CURRENT_USER, keyname.c_str(), 0,
589 KEY_READ|KEY_WRITE, &hkey);
590 if (ERROR_SUCCESS == result)
592 // Create the subkey and set the values of interest:
593 HKEY hsubkey = NULL;
594 result = RegCreateKeyEx(hkey, nextAvailableSubKeyName.c_str(), 0, "", 0,
595 KEY_READ|KEY_WRITE, 0, &hsubkey, 0);
596 if (ERROR_SUCCESS == result)
598 DWORD dw = 0;
600 std::string s(macrosFile);
601 cmSystemTools::ReplaceString(s, "/", "\\");
603 result = RegSetValueEx(hsubkey, "Path", 0, REG_SZ, (LPBYTE) s.c_str(),
604 static_cast<DWORD>(strlen(s.c_str()) + 1));
605 if (ERROR_SUCCESS != result)
607 std::cout << "error result 1: " << result << std::endl;
608 std::cout << std::endl;
611 // Security value is always "1" for sample macros files (seems to be "2"
612 // if you put the file somewhere outside the standard VSMacros folder)
613 dw = 1;
614 result = RegSetValueEx(hsubkey, "Security",
615 0, REG_DWORD, (LPBYTE) &dw, sizeof(DWORD));
616 if (ERROR_SUCCESS != result)
618 std::cout << "error result 2: " << result << std::endl;
619 std::cout << std::endl;
622 // StorageFormat value is always "0" for sample macros files
623 dw = 0;
624 result = RegSetValueEx(hsubkey, "StorageFormat",
625 0, REG_DWORD, (LPBYTE) &dw, sizeof(DWORD));
626 if (ERROR_SUCCESS != result)
628 std::cout << "error result 3: " << result << std::endl;
629 std::cout << std::endl;
632 RegCloseKey(hsubkey);
634 else
636 std::cout << "error creating subkey: "
637 << nextAvailableSubKeyName << std::endl;
638 std::cout << std::endl;
640 RegCloseKey(hkey);
642 else
644 std::cout << "error opening key: " << keyname << std::endl;
645 std::cout << std::endl;
649 //----------------------------------------------------------------------------
650 void RegisterVisualStudioMacros(const std::string& macrosFile,
651 const std::string& regKeyBase)
653 bool macrosRegistered;
654 std::string nextAvailableSubKeyName;
656 macrosRegistered = IsVisualStudioMacrosFileRegistered(macrosFile,
657 regKeyBase, nextAvailableSubKeyName);
659 if (!macrosRegistered)
661 int count = cmCallVisualStudioMacro::
662 GetNumberOfRunningVisualStudioInstances("ALL");
664 // Only register the macros file if there are *no* instances of Visual
665 // Studio running. If we register it while one is running, first, it has
666 // no effect on the running instance; second, and worse, Visual Studio
667 // removes our newly added registration entry when it quits. Instead,
668 // emit a warning asking the user to exit all running Visual Studio
669 // instances...
671 if (0 != count)
673 std::ostringstream oss;
674 oss << "Could not register CMake's Visual Studio macros file '"
675 << CMAKE_VSMACROS_FILENAME "' while Visual Studio is running."
676 << " Please exit all running instances of Visual Studio before"
677 << " continuing." << std::endl
678 << std::endl
679 << "CMake needs to register Visual Studio macros when its macros"
680 << " file is updated or when it detects that its current macros file"
681 << " is no longer registered with Visual Studio."
682 << std::endl;
683 cmSystemTools::Message(oss.str().c_str(), "Warning");
685 // Count them again now that the warning is over. In the case of a GUI
686 // warning, the user may have gone to close Visual Studio and then come
687 // back to the CMake GUI and clicked ok on the above warning. If so,
688 // then register the macros *now* if the count is *now* 0...
690 count = cmCallVisualStudioMacro::
691 GetNumberOfRunningVisualStudioInstances("ALL");
693 // Also re-get the nextAvailableSubKeyName in case Visual Studio
694 // wrote out new registered macros information as it was exiting:
696 if (0 == count)
698 IsVisualStudioMacrosFileRegistered(macrosFile, regKeyBase,
699 nextAvailableSubKeyName);
703 // Do another if check - 'count' may have changed inside the above if:
705 if (0 == count)
707 WriteVSMacrosFileRegistryEntry(nextAvailableSubKeyName, macrosFile,
708 regKeyBase);
712 bool cmGlobalVisualStudioGenerator::TargetIsFortranOnly(cmTarget& target)
714 // check to see if this is a fortran build
715 std::set<cmStdString> languages;
716 target.GetLanguages(languages);
717 if(languages.size() == 1)
719 if(*languages.begin() == "Fortran")
721 return true;
724 return false;