ef2bb1d992e66bf882b45da9b163f453e59aaa7d
[platform/upstream/cmake.git] / Source / cmLocalVisualStudioGenerator.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4
5   Distributed under the OSI-approved BSD License (the "License");
6   see accompanying file Copyright.txt for details.
7
8   This software is distributed WITHOUT ANY WARRANTY; without even the
9   implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10   See the License for more information.
11 ============================================================================*/
12 #include "cmLocalVisualStudioGenerator.h"
13 #include "cmGlobalGenerator.h"
14 #include "cmMakefile.h"
15 #include "cmSourceFile.h"
16 #include "cmSystemTools.h"
17 #include "cmCustomCommandGenerator.h"
18 #include "windows.h"
19
20 //----------------------------------------------------------------------------
21 cmLocalVisualStudioGenerator::cmLocalVisualStudioGenerator(VSVersion v)
22 {
23   this->WindowsShell = true;
24   this->WindowsVSIDE = true;
25   this->Version = v;
26 }
27
28 //----------------------------------------------------------------------------
29 cmLocalVisualStudioGenerator::~cmLocalVisualStudioGenerator()
30 {
31 }
32
33 //----------------------------------------------------------------------------
34 cmsys::auto_ptr<cmCustomCommand>
35 cmLocalVisualStudioGenerator::MaybeCreateImplibDir(cmTarget& target,
36                                                    const char* config,
37                                                    bool isFortran)
38 {
39   cmsys::auto_ptr<cmCustomCommand> pcc;
40
41   // If an executable exports symbols then VS wants to create an
42   // import library but forgets to create the output directory.
43   // The Intel Fortran plugin always forgets to the directory.
44   if(target.GetType() != cmTarget::EXECUTABLE &&
45      !(isFortran && target.GetType() == cmTarget::SHARED_LIBRARY))
46     { return pcc; }
47   std::string outDir = target.GetDirectory(config, false);
48   std::string impDir = target.GetDirectory(config, true);
49   if(impDir == outDir) { return pcc; }
50
51   // Add a pre-build event to create the directory.
52   cmCustomCommandLine command;
53   command.push_back(this->Makefile->GetRequiredDefinition("CMAKE_COMMAND"));
54   command.push_back("-E");
55   command.push_back("make_directory");
56   command.push_back(impDir);
57   std::vector<std::string> no_output;
58   std::vector<std::string> no_depends;
59   cmCustomCommandLines commands;
60   commands.push_back(command);
61   pcc.reset(new cmCustomCommand(0, no_output, no_depends, commands, 0, 0));
62   pcc->SetEscapeOldStyle(false);
63   pcc->SetEscapeAllowMakeVars(true);
64   return pcc;
65 }
66
67 //----------------------------------------------------------------------------
68 const char* cmLocalVisualStudioGenerator::ReportErrorLabel() const
69 {
70   return ":VCReportError";
71 }
72
73 //----------------------------------------------------------------------------
74 const char* cmLocalVisualStudioGenerator::GetReportErrorLabel() const
75 {
76   return this->ReportErrorLabel();
77 }
78
79 //----------------------------------------------------------------------------
80 std::string
81 cmLocalVisualStudioGenerator
82 ::ConstructScript(cmCustomCommand const& cc,
83                   const char* configName,
84                   const char* newline_text)
85 {
86   bool useLocal = this->CustomCommandUseLocal();
87   const char* workingDirectory = cc.GetWorkingDirectory();
88   cmCustomCommandGenerator ccg(cc, configName, this->Makefile);
89   RelativeRoot relativeRoot = workingDirectory? NONE : START_OUTPUT;
90
91   // Avoid leading or trailing newlines.
92   const char* newline = "";
93
94   // Line to check for error between commands.
95   std::string check_error = newline_text;
96   if(useLocal)
97     {
98     check_error += "if %errorlevel% neq 0 goto :cmEnd";
99     }
100   else
101     {
102     check_error += "if errorlevel 1 goto ";
103     check_error += this->GetReportErrorLabel();
104     }
105
106   // Store the script in a string.
107   std::string script;
108
109   // Open a local context.
110   if(useLocal)
111     {
112     script += newline;
113     newline = newline_text;
114     script += "setlocal";
115     }
116
117   if(workingDirectory)
118     {
119     // Change the working directory.
120     script += newline;
121     newline = newline_text;
122     script += "cd ";
123     script += this->Convert(workingDirectory, FULL, SHELL);
124     script += check_error;
125
126     // Change the working drive.
127     if(workingDirectory[0] && workingDirectory[1] == ':')
128       {
129       script += newline;
130       newline = newline_text;
131       script += workingDirectory[0];
132       script += workingDirectory[1];
133       script += check_error;
134       }
135     }
136
137   // for visual studio IDE add extra stuff to the PATH
138   // if CMAKE_MSVCIDE_RUN_PATH is set.
139   if(this->Makefile->GetDefinition("MSVC_IDE"))
140     {
141     const char* extraPath =
142       this->Makefile->GetDefinition("CMAKE_MSVCIDE_RUN_PATH");
143     if(extraPath)
144       {
145       script += newline;
146       newline = newline_text;
147       script += "set PATH=";
148       script += extraPath;
149       script += ";%PATH%";
150       }
151     }
152
153   // Write each command on a single line.
154   for(unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c)
155     {
156     // Start a new line.
157     script += newline;
158     newline = newline_text;
159
160     // Add this command line.
161     std::string cmd = ccg.GetCommand(c);
162
163     // Use "call " before any invocations of .bat or .cmd files
164     // invoked as custom commands.
165     //
166     std::string suffix;
167     if (cmd.size() > 4)
168       {
169       suffix = cmSystemTools::LowerCase(cmd.substr(cmd.size()-4));
170       if (suffix == ".bat" || suffix == ".cmd")
171         {
172         script += "call ";
173         }
174       }
175
176     script += this->Convert(cmd.c_str(), relativeRoot, SHELL);
177     ccg.AppendArguments(c, script);
178
179     // After each custom command, check for an error result.
180     // If there was an error, jump to the VCReportError label,
181     // skipping the run of any subsequent commands in this
182     // sequence.
183     script += check_error;
184     }
185
186   // Close the local context.
187   if(useLocal)
188     {
189     script += newline;
190     script += ":cmEnd";
191     script += newline;
192     script += "endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone";
193     script += newline;
194     script += ":cmErrorLevel";
195     script += newline;
196     script += "exit /b %1";
197     script += newline;
198     script += ":cmDone";
199     script += newline;
200     script += "if %errorlevel% neq 0 goto ";
201     script += this->GetReportErrorLabel();
202     }
203
204   return script;
205 }