1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmGlobalVisualStudioGenerator.cxx,v $
6 Date: $Date: 2009-09-16 15:44:08 $
7 Version: $Revision: 1.17 $
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"
24 //----------------------------------------------------------------------------
25 cmGlobalVisualStudioGenerator::cmGlobalVisualStudioGenerator()
29 //----------------------------------------------------------------------------
30 cmGlobalVisualStudioGenerator::~cmGlobalVisualStudioGenerator()
34 //----------------------------------------------------------------------------
35 std::string
cmGlobalVisualStudioGenerator::GetRegistryBase()
37 std::string key
= "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\";
38 key
+= this->GetIDEVersion();
42 //----------------------------------------------------------------------------
43 void cmGlobalVisualStudioGenerator::Generate()
45 // Add a special target that depends on ALL projects for easy build
46 // of one configuration only.
47 const char* no_working_dir
= 0;
48 std::vector
<std::string
> no_depends
;
49 cmCustomCommandLines no_commands
;
50 std::map
<cmStdString
, std::vector
<cmLocalGenerator
*> >::iterator it
;
51 for(it
= this->ProjectMap
.begin(); it
!= this->ProjectMap
.end(); ++it
)
53 std::vector
<cmLocalGenerator
*>& gen
= it
->second
;
54 // add the ALL_BUILD to the first local generator of each project
57 // Use no actual command lines so that the target itself is not
58 // considered always out of date.
60 gen
[0]->GetMakefile()->
61 AddUtilityCommand("ALL_BUILD", true, no_working_dir
,
62 no_depends
, no_commands
, false,
63 "Build all projects");
64 // Now make all targets depend on the ALL_BUILD target
66 for(std::vector
<cmLocalGenerator
*>::iterator i
= gen
.begin();
69 cmTargets
& targets
= (*i
)->GetMakefile()->GetTargets();
70 for(cmTargets::iterator t
= targets
.begin();
71 t
!= targets
.end(); ++t
)
73 if(!this->IsExcluded(gen
[0], t
->second
))
75 allBuild
->AddUtility(t
->second
.GetName());
82 // Fix utility dependencies to avoid linking to libraries.
83 this->FixUtilityDepends();
85 // Configure CMake Visual Studio macros, for this user on this version
87 this->ConfigureCMakeVisualStudioMacros();
89 // Run all the local generators.
90 this->cmGlobalGenerator::Generate();
93 //----------------------------------------------------------------------------
94 bool IsVisualStudioMacrosFileRegistered(const std::string
& macrosFile
,
95 const std::string
& regKeyBase
,
96 std::string
& nextAvailableSubKeyName
);
98 void RegisterVisualStudioMacros(const std::string
& macrosFile
,
99 const std::string
& regKeyBase
);
101 //----------------------------------------------------------------------------
102 #define CMAKE_VSMACROS_FILENAME \
103 "CMakeVSMacros2.vsmacros"
105 #define CMAKE_VSMACROS_RELOAD_MACRONAME \
106 "Macros.CMakeVSMacros2.Macros.ReloadProjects"
108 #define CMAKE_VSMACROS_STOP_MACRONAME \
109 "Macros.CMakeVSMacros2.Macros.StopBuild"
111 //----------------------------------------------------------------------------
112 void cmGlobalVisualStudioGenerator::ConfigureCMakeVisualStudioMacros()
114 cmMakefile
* mf
= this->LocalGenerators
[0]->GetMakefile();
115 std::string dir
= this->GetUserMacrosDirectory();
117 if (mf
!= 0 && dir
!= "")
119 std::string src
= mf
->GetRequiredDefinition("CMAKE_ROOT");
120 src
+= "/Templates/" CMAKE_VSMACROS_FILENAME
;
122 std::string dst
= dir
+ "/CMakeMacros/" CMAKE_VSMACROS_FILENAME
;
124 // Copy the macros file to the user directory only if the
125 // destination does not exist or the source location is newer.
126 // This will allow the user to edit the macros for development
127 // purposes but newer versions distributed with CMake will replace
128 // older versions in user directories.
130 if(!cmSystemTools::FileTimeCompare(src
.c_str(), dst
.c_str(), &res
) ||
133 if (!cmSystemTools::CopyFileAlways(src
.c_str(), dst
.c_str()))
135 std::ostringstream oss
;
136 oss
<< "Could not copy from: " << src
<< std::endl
;
137 oss
<< " to: " << dst
<< std::endl
;
138 cmSystemTools::Message(oss
.str().c_str(), "Warning");
142 RegisterVisualStudioMacros(dst
, this->GetUserMacrosRegKeyBase());
146 //----------------------------------------------------------------------------
148 cmGlobalVisualStudioGenerator
149 ::CallVisualStudioMacro(MacroName m
,
150 const char* vsSolutionFile
)
152 // If any solution or project files changed during the generation,
153 // tell Visual Studio to reload them...
154 cmMakefile
* mf
= this->LocalGenerators
[0]->GetMakefile();
155 std::string dir
= this->GetUserMacrosDirectory();
157 // Only really try to call the macro if:
159 // - there is a UserMacrosDirectory
160 // - the CMake vsmacros file exists
161 // - the CMake vsmacros file is registered
162 // - there were .sln/.vcproj files changed during generation
164 if (mf
!= 0 && dir
!= "")
166 std::string macrosFile
= dir
+ "/CMakeMacros/" CMAKE_VSMACROS_FILENAME
;
167 std::string nextSubkeyName
;
168 if (cmSystemTools::FileExists(macrosFile
.c_str()) &&
169 IsVisualStudioMacrosFileRegistered(macrosFile
,
170 this->GetUserMacrosRegKeyBase(), nextSubkeyName
)
173 std::string topLevelSlnName
;
176 topLevelSlnName
= vsSolutionFile
;
180 topLevelSlnName
= mf
->GetStartOutputDirectory();
181 topLevelSlnName
+= "/";
182 topLevelSlnName
+= mf
->GetProjectName();
183 topLevelSlnName
+= ".sln";
188 std::vector
<std::string
> filenames
;
189 this->GetFilesReplacedDuringGenerate(filenames
);
190 if (filenames
.size() > 0)
192 // Convert vector to semi-colon delimited string of filenames:
193 std::string projects
;
194 std::vector
<std::string
>::iterator it
= filenames
.begin();
195 if (it
!= filenames
.end())
200 for (; it
!= filenames
.end(); ++it
)
205 cmCallVisualStudioMacro::CallMacro(topLevelSlnName
,
206 CMAKE_VSMACROS_RELOAD_MACRONAME
, projects
,
207 this->GetCMakeInstance()->GetDebugOutput());
210 else if(m
== MacroStop
)
212 cmCallVisualStudioMacro::CallMacro(topLevelSlnName
,
213 CMAKE_VSMACROS_STOP_MACRONAME
, "",
214 this->GetCMakeInstance()->GetDebugOutput());
220 //----------------------------------------------------------------------------
221 std::string
cmGlobalVisualStudioGenerator::GetUserMacrosDirectory()
226 //----------------------------------------------------------------------------
227 std::string
cmGlobalVisualStudioGenerator::GetUserMacrosRegKeyBase()
232 //----------------------------------------------------------------------------
233 void cmGlobalVisualStudioGenerator::FixUtilityDepends()
235 // Skip for VS versions 8 and above.
236 if(!this->VSLinksDependencies())
241 // For VS versions before 8:
243 // When a target that links contains a project-level dependency on a
244 // library target that library is automatically linked. In order to
245 // allow utility-style project-level dependencies that do not
246 // actually link we need to automatically insert an intermediate
249 // Here we edit the utility dependencies of a target to add the
250 // intermediate custom target when necessary.
251 for(unsigned i
= 0; i
< this->LocalGenerators
.size(); ++i
)
254 &(this->LocalGenerators
[i
]->GetMakefile()->GetTargets());
255 for(cmTargets::iterator tarIt
= targets
->begin();
256 tarIt
!= targets
->end(); ++tarIt
)
258 this->FixUtilityDependsForTarget(tarIt
->second
);
263 //----------------------------------------------------------------------------
265 cmGlobalVisualStudioGenerator::FixUtilityDependsForTarget(cmTarget
& target
)
267 // Only targets that link need to be fixed.
268 if(target
.GetType() != cmTarget::STATIC_LIBRARY
&&
269 target
.GetType() != cmTarget::SHARED_LIBRARY
&&
270 target
.GetType() != cmTarget::MODULE_LIBRARY
&&
271 target
.GetType() != cmTarget::EXECUTABLE
)
277 // This feature makes a mess in SLN files for VS 7.1 and below. It
278 // creates an extra target for every target that is "linked" by a
279 // static library. Without this feature static libraries do not
280 // wait until their "link" dependencies are built to build. This is
281 // not a problem 99.9% of the time, and projects that do have the
282 // problem can enable this work-around by using add_dependencies.
284 // Static libraries cannot depend directly on the targets to which
285 // they link because VS will copy those targets into the library
286 // (for VS < 8). To work around the problem we copy the
287 // dependencies to be utility dependencies so that the work-around
289 if(target
.GetType() == cmTarget::STATIC_LIBRARY
)
291 cmTarget::LinkLibraryVectorType
const& libs
= target
.GetLinkLibraries();
292 for(cmTarget::LinkLibraryVectorType::const_iterator i
= libs
.begin();
293 i
!= libs
.end(); ++i
)
295 if(cmTarget
* depTarget
= this->FindTarget(0, i
->first
.c_str(), false))
297 target
.AddUtility(depTarget
->GetName());
303 // Look at each utility dependency.
304 for(std::set
<cmStdString
>::const_iterator ui
=
305 target
.GetUtilities().begin();
306 ui
!= target
.GetUtilities().end(); ++ui
)
308 if(cmTarget
* depTarget
= this->FindTarget(0, ui
->c_str()))
310 if(depTarget
->GetType() == cmTarget::STATIC_LIBRARY
||
311 depTarget
->GetType() == cmTarget::SHARED_LIBRARY
||
312 depTarget
->GetType() == cmTarget::MODULE_LIBRARY
)
314 // This utility dependency will cause an attempt to link. If
315 // the depender does not already link the dependee we need an
316 // intermediate target.
317 if(!this->CheckTargetLinks(target
, ui
->c_str()))
319 this->CreateUtilityDependTarget(*depTarget
);
326 //----------------------------------------------------------------------------
328 cmGlobalVisualStudioGenerator::CreateUtilityDependTarget(cmTarget
& target
)
330 // This target is a library on which a utility dependency exists.
331 // We need to create an intermediate custom target to hook up the
332 // dependency without causing a link.
333 const char* altName
= target
.GetProperty("ALTERNATIVE_DEPENDENCY_NAME");
336 // Create the intermediate utility target.
337 std::string altNameStr
= target
.GetName();
338 altNameStr
+= "_UTILITY";
339 const std::vector
<std::string
> no_depends
;
340 cmCustomCommandLines no_commands
;
341 const char* no_working_dir
= 0;
342 const char* no_comment
= 0;
343 target
.GetMakefile()->AddUtilityCommand(altNameStr
.c_str(), true,
344 no_working_dir
, no_depends
,
345 no_commands
, false, no_comment
);
346 target
.SetProperty("ALTERNATIVE_DEPENDENCY_NAME", altNameStr
.c_str());
348 // Most targets have a GUID created in ConfigureFinalPass. Since
349 // that has already been called, create one for this target now.
350 this->CreateGUID(altNameStr
.c_str());
352 // The intermediate target should depend on the original target.
353 if(cmTarget
* alt
= this->FindTarget(0, altNameStr
.c_str()))
355 alt
->AddUtility(target
.GetName());
360 //----------------------------------------------------------------------------
361 bool cmGlobalVisualStudioGenerator::CheckTargetLinks(cmTarget
& target
,
364 // Return whether the given target links to a target with the given name.
365 if(target
.GetType() == cmTarget::STATIC_LIBRARY
)
367 // Static libraries never link to anything.
370 cmTarget::LinkLibraryVectorType
const& libs
= target
.GetLinkLibraries();
371 for(cmTarget::LinkLibraryVectorType::const_iterator i
= libs
.begin();
372 i
!= libs
.end(); ++i
)
382 //----------------------------------------------------------------------------
384 cmGlobalVisualStudioGenerator::GetUtilityForTarget(cmTarget
& target
,
387 // Possibly depend on an intermediate utility target to avoid
389 if(target
.GetType() == cmTarget::STATIC_LIBRARY
||
390 target
.GetType() == cmTarget::SHARED_LIBRARY
||
391 target
.GetType() == cmTarget::MODULE_LIBRARY
||
392 target
.GetType() == cmTarget::EXECUTABLE
)
394 // The depender is a target that links. Lookup the dependee to
395 // see if it provides an alternative dependency name.
396 if(cmTarget
* depTarget
= this->FindTarget(0, name
))
398 // Check for an alternative name created by FixUtilityDepends.
399 if(const char* altName
=
400 depTarget
->GetProperty("ALTERNATIVE_DEPENDENCY_NAME"))
402 // The alternative name is needed only if the depender does
403 // not really link to the dependee.
404 if(!this->CheckTargetLinks(target
, name
))
412 // No special case. Just use the original dependency name.
416 //----------------------------------------------------------------------------
419 //----------------------------------------------------------------------------
420 bool IsVisualStudioMacrosFileRegistered(const std::string
& macrosFile
,
421 const std::string
& regKeyBase
,
422 std::string
& nextAvailableSubKeyName
)
424 bool macrosRegistered
= false;
429 // Make lowercase local copies, convert to Unix slashes, and
430 // see if the resulting strings are the same:
431 s1
= cmSystemTools::LowerCase(macrosFile
);
432 cmSystemTools::ConvertToUnixSlashes(s1
);
436 LONG result
= ERROR_SUCCESS
;
439 keyname
= regKeyBase
+ "\\OtherProjects7";
441 result
= RegOpenKeyEx(HKEY_CURRENT_USER
, keyname
.c_str(),
443 if (ERROR_SUCCESS
== result
)
445 // Iterate the subkeys and look for the values of interest in each subkey:
446 CHAR subkeyname
[256];
447 DWORD cch_subkeyname
= sizeof(subkeyname
)/sizeof(subkeyname
[0]);
449 DWORD cch_keyclass
= sizeof(keyclass
)/sizeof(keyclass
[0]);
450 FILETIME lastWriteTime
;
451 lastWriteTime
.dwHighDateTime
= 0;
452 lastWriteTime
.dwLowDateTime
= 0;
454 while (ERROR_SUCCESS
== RegEnumKeyEx(hkey
, index
, subkeyname
,
456 0, keyclass
, &cch_keyclass
, &lastWriteTime
))
458 // Open the subkey and query the values of interest:
460 result
= RegOpenKeyEx(hkey
, subkeyname
, 0, KEY_READ
, &hsubkey
);
461 if (ERROR_SUCCESS
== result
)
463 DWORD valueType
= REG_SZ
;
465 DWORD cch_data1
= sizeof(data1
)/sizeof(data1
[0]);
466 RegQueryValueEx(hsubkey
, "Path", 0, &valueType
,
467 (LPBYTE
) &data1
[0], &cch_data1
);
470 DWORD cch_data2
= sizeof(data2
);
471 RegQueryValueEx(hsubkey
, "Security", 0, &valueType
,
472 (LPBYTE
) &data2
, &cch_data2
);
475 DWORD cch_data3
= sizeof(data3
);
476 RegQueryValueEx(hsubkey
, "StorageFormat", 0, &valueType
,
477 (LPBYTE
) &data3
, &cch_data3
);
479 s2
= cmSystemTools::LowerCase(data1
);
480 cmSystemTools::ConvertToUnixSlashes(s2
);
483 macrosRegistered
= true;
486 std::string
fullname(data1
);
487 std::string filename
;
488 std::string filepath
;
489 std::string filepathname
;
490 std::string filepathpath
;
491 if (cmSystemTools::FileExists(fullname
.c_str()))
493 filename
= cmSystemTools::GetFilenameName(fullname
);
494 filepath
= cmSystemTools::GetFilenamePath(fullname
);
495 filepathname
= cmSystemTools::GetFilenameName(filepath
);
496 filepathpath
= cmSystemTools::GetFilenamePath(filepath
);
499 //std::cout << keyname << "\\" << subkeyname << ":" << std::endl;
500 //std::cout << " Path: " << data1 << std::endl;
501 //std::cout << " Security: " << data2 << std::endl;
502 //std::cout << " StorageFormat: " << data3 << std::endl;
503 //std::cout << " filename: " << filename << std::endl;
504 //std::cout << " filepath: " << filepath << std::endl;
505 //std::cout << " filepathname: " << filepathname << std::endl;
506 //std::cout << " filepathpath: " << filepathpath << std::endl;
507 //std::cout << std::endl;
509 RegCloseKey(hsubkey
);
513 std::cout
<< "error opening subkey: " << subkeyname
<< std::endl
;
514 std::cout
<< std::endl
;
518 cch_subkeyname
= sizeof(subkeyname
)/sizeof(subkeyname
[0]);
519 cch_keyclass
= sizeof(keyclass
)/sizeof(keyclass
[0]);
520 lastWriteTime
.dwHighDateTime
= 0;
521 lastWriteTime
.dwLowDateTime
= 0;
528 std::cout
<< "error opening key: " << keyname
<< std::endl
;
529 std::cout
<< std::endl
;
533 // Pass back next available sub key name, assuming sub keys always
534 // follow the expected naming scheme. Expected naming scheme is that
535 // the subkeys of OtherProjects7 is 0 to n-1, so it's ok to use "n"
536 // as the name of the next subkey.
537 std::ostringstream ossNext
;
539 nextAvailableSubKeyName
= ossNext
.str();
542 keyname
= regKeyBase
+ "\\RecordingProject7";
544 result
= RegOpenKeyEx(HKEY_CURRENT_USER
, keyname
.c_str(),
546 if (ERROR_SUCCESS
== result
)
548 DWORD valueType
= REG_SZ
;
550 DWORD cch_data1
= sizeof(data1
)/sizeof(data1
[0]);
551 RegQueryValueEx(hkey
, "Path", 0, &valueType
,
552 (LPBYTE
) &data1
[0], &cch_data1
);
555 DWORD cch_data2
= sizeof(data2
);
556 RegQueryValueEx(hkey
, "Security", 0, &valueType
,
557 (LPBYTE
) &data2
, &cch_data2
);
560 DWORD cch_data3
= sizeof(data3
);
561 RegQueryValueEx(hkey
, "StorageFormat", 0, &valueType
,
562 (LPBYTE
) &data3
, &cch_data3
);
564 s2
= cmSystemTools::LowerCase(data1
);
565 cmSystemTools::ConvertToUnixSlashes(s2
);
568 macrosRegistered
= true;
571 //std::cout << keyname << ":" << std::endl;
572 //std::cout << " Path: " << data1 << std::endl;
573 //std::cout << " Security: " << data2 << std::endl;
574 //std::cout << " StorageFormat: " << data3 << std::endl;
575 //std::cout << std::endl;
581 std::cout
<< "error opening key: " << keyname
<< std::endl
;
582 std::cout
<< std::endl
;
585 return macrosRegistered
;
588 //----------------------------------------------------------------------------
589 void WriteVSMacrosFileRegistryEntry(
590 const std::string
& nextAvailableSubKeyName
,
591 const std::string
& macrosFile
,
592 const std::string
& regKeyBase
)
594 std::string keyname
= regKeyBase
+ "\\OtherProjects7";
596 LONG result
= RegOpenKeyEx(HKEY_CURRENT_USER
, keyname
.c_str(), 0,
597 KEY_READ
|KEY_WRITE
, &hkey
);
598 if (ERROR_SUCCESS
== result
)
600 // Create the subkey and set the values of interest:
602 result
= RegCreateKeyEx(hkey
, nextAvailableSubKeyName
.c_str(), 0, "", 0,
603 KEY_READ
|KEY_WRITE
, 0, &hsubkey
, 0);
604 if (ERROR_SUCCESS
== result
)
608 std::string
s(macrosFile
);
609 cmSystemTools::ReplaceString(s
, "/", "\\");
611 result
= RegSetValueEx(hsubkey
, "Path", 0, REG_SZ
, (LPBYTE
) s
.c_str(),
612 static_cast<DWORD
>(strlen(s
.c_str()) + 1));
613 if (ERROR_SUCCESS
!= result
)
615 std::cout
<< "error result 1: " << result
<< std::endl
;
616 std::cout
<< std::endl
;
619 // Security value is always "1" for sample macros files (seems to be "2"
620 // if you put the file somewhere outside the standard VSMacros folder)
622 result
= RegSetValueEx(hsubkey
, "Security",
623 0, REG_DWORD
, (LPBYTE
) &dw
, sizeof(DWORD
));
624 if (ERROR_SUCCESS
!= result
)
626 std::cout
<< "error result 2: " << result
<< std::endl
;
627 std::cout
<< std::endl
;
630 // StorageFormat value is always "0" for sample macros files
632 result
= RegSetValueEx(hsubkey
, "StorageFormat",
633 0, REG_DWORD
, (LPBYTE
) &dw
, sizeof(DWORD
));
634 if (ERROR_SUCCESS
!= result
)
636 std::cout
<< "error result 3: " << result
<< std::endl
;
637 std::cout
<< std::endl
;
640 RegCloseKey(hsubkey
);
644 std::cout
<< "error creating subkey: "
645 << nextAvailableSubKeyName
<< std::endl
;
646 std::cout
<< std::endl
;
652 std::cout
<< "error opening key: " << keyname
<< std::endl
;
653 std::cout
<< std::endl
;
657 //----------------------------------------------------------------------------
658 void RegisterVisualStudioMacros(const std::string
& macrosFile
,
659 const std::string
& regKeyBase
)
661 bool macrosRegistered
;
662 std::string nextAvailableSubKeyName
;
664 macrosRegistered
= IsVisualStudioMacrosFileRegistered(macrosFile
,
665 regKeyBase
, nextAvailableSubKeyName
);
667 if (!macrosRegistered
)
669 int count
= cmCallVisualStudioMacro::
670 GetNumberOfRunningVisualStudioInstances("ALL");
672 // Only register the macros file if there are *no* instances of Visual
673 // Studio running. If we register it while one is running, first, it has
674 // no effect on the running instance; second, and worse, Visual Studio
675 // removes our newly added registration entry when it quits. Instead,
676 // emit a warning asking the user to exit all running Visual Studio
681 std::ostringstream oss
;
682 oss
<< "Could not register CMake's Visual Studio macros file '"
683 << CMAKE_VSMACROS_FILENAME
"' while Visual Studio is running."
684 << " Please exit all running instances of Visual Studio before"
685 << " continuing." << std::endl
687 << "CMake needs to register Visual Studio macros when its macros"
688 << " file is updated or when it detects that its current macros file"
689 << " is no longer registered with Visual Studio."
691 cmSystemTools::Message(oss
.str().c_str(), "Warning");
693 // Count them again now that the warning is over. In the case of a GUI
694 // warning, the user may have gone to close Visual Studio and then come
695 // back to the CMake GUI and clicked ok on the above warning. If so,
696 // then register the macros *now* if the count is *now* 0...
698 count
= cmCallVisualStudioMacro::
699 GetNumberOfRunningVisualStudioInstances("ALL");
701 // Also re-get the nextAvailableSubKeyName in case Visual Studio
702 // wrote out new registered macros information as it was exiting:
706 IsVisualStudioMacrosFileRegistered(macrosFile
, regKeyBase
,
707 nextAvailableSubKeyName
);
711 // Do another if check - 'count' may have changed inside the above if:
715 WriteVSMacrosFileRegistryEntry(nextAvailableSubKeyName
, macrosFile
,
720 bool cmGlobalVisualStudioGenerator::TargetIsFortranOnly(cmTarget
& target
)
722 // check to see if this is a fortran build
723 std::set
<cmStdString
> languages
;
724 target
.GetLanguages(languages
);
725 if(languages
.size() == 1)
727 if(*languages
.begin() == "Fortran")