Imported Upstream version 2.8.9
[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 cmCustomCommandLines& commandLines = cc.GetCommandLines();
88   const char* workingDirectory = cc.GetWorkingDirectory();
89   cmCustomCommandGenerator ccg(cc, configName, this->Makefile);
90   RelativeRoot relativeRoot = workingDirectory? NONE : START_OUTPUT;
91
92   // Avoid leading or trailing newlines.
93   const char* newline = "";
94
95   // Line to check for error between commands.
96   std::string check_error = newline_text;
97   if(useLocal)
98     {
99     check_error += "if %errorlevel% neq 0 goto :cmEnd";
100     }
101   else
102     {
103     check_error += "if errorlevel 1 goto ";
104     check_error += this->GetReportErrorLabel();
105     }
106
107   // Store the script in a string.
108   std::string script;
109
110   // Open a local context.
111   if(useLocal)
112     {
113     script += newline;
114     newline = newline_text;
115     script += "setlocal";
116     }
117
118   if(workingDirectory)
119     {
120     // Change the working directory.
121     script += newline;
122     newline = newline_text;
123     script += "cd ";
124     script += this->Convert(workingDirectory, FULL, SHELL);
125     script += check_error;
126
127     // Change the working drive.
128     if(workingDirectory[0] && workingDirectory[1] == ':')
129       {
130       script += newline;
131       newline = newline_text;
132       script += workingDirectory[0];
133       script += workingDirectory[1];
134       script += check_error;
135       }
136     }
137
138   // for visual studio IDE add extra stuff to the PATH
139   // if CMAKE_MSVCIDE_RUN_PATH is set.
140   if(this->Makefile->GetDefinition("MSVC_IDE"))
141     {
142     const char* extraPath =
143       this->Makefile->GetDefinition("CMAKE_MSVCIDE_RUN_PATH");
144     if(extraPath)
145       {
146       script += newline;
147       newline = newline_text;
148       script += "set PATH=";
149       script += extraPath;
150       script += ";%PATH%";
151       }
152     }
153
154   // Write each command on a single line.
155   for(unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c)
156     {
157     // Start a new line.
158     script += newline;
159     newline = newline_text;
160
161     // Add this command line.
162     std::string cmd = ccg.GetCommand(c);
163
164     // Use "call " before any invocations of .bat or .cmd files
165     // invoked as custom commands.
166     //
167     std::string suffix;
168     if (cmd.size() > 4)
169       {
170       suffix = cmSystemTools::LowerCase(cmd.substr(cmd.size()-4));
171       if (suffix == ".bat" || suffix == ".cmd")
172         {
173         script += "call ";
174         }
175       }
176
177     script += this->Convert(cmd.c_str(), relativeRoot, SHELL);
178     ccg.AppendArguments(c, script);
179
180     // After each custom command, check for an error result.
181     // If there was an error, jump to the VCReportError label,
182     // skipping the run of any subsequent commands in this
183     // sequence.
184     script += check_error;
185     }
186
187   // Close the local context.
188   if(useLocal)
189     {
190     script += newline;
191     script += ":cmEnd";
192     script += newline;
193     script += "endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone";
194     script += newline;
195     script += ":cmErrorLevel";
196     script += newline;
197     script += "exit /b %1";
198     script += newline;
199     script += ":cmDone";
200     script += newline;
201     script += "if %errorlevel% neq 0 goto ";
202     script += this->GetReportErrorLabel();
203     }
204
205   return script;
206 }