cmake/Source/cmLocalVisualStudioGenerator.cxx

263 lines
7.6 KiB
C++
Raw Normal View History

2016-10-30 18:24:19 +01:00
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmLocalVisualStudioGenerator.h"
2016-07-09 11:21:54 +02:00
2022-03-29 21:10:50 +02:00
#include <utility>
2023-05-23 16:38:00 +02:00
#include <cm/memory>
2020-02-01 23:06:01 +01:00
#include "windows.h"
2019-11-11 23:01:05 +01:00
#include "cmCustomCommand.h"
2016-07-09 11:21:54 +02:00
#include "cmCustomCommandGenerator.h"
2022-03-29 21:10:50 +02:00
#include "cmCustomCommandLines.h"
2016-10-30 18:24:19 +01:00
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
2022-03-29 21:10:50 +02:00
#include "cmOutputConverter.h"
#include "cmSourceFile.h"
2022-03-29 21:10:50 +02:00
#include "cmStateTypes.h"
#include "cmSystemTools.h"
2022-03-29 21:10:50 +02:00
#include "cmValue.h"
2016-07-09 11:21:54 +02:00
cmLocalVisualStudioGenerator::cmLocalVisualStudioGenerator(
cmGlobalGenerator* gg, cmMakefile* mf)
2015-11-17 17:22:37 +01:00
: cmLocalGenerator(gg, mf)
{
}
2023-05-23 16:38:00 +02:00
cmLocalVisualStudioGenerator::~cmLocalVisualStudioGenerator() = default;
2015-08-17 11:37:30 +02:00
cmGlobalVisualStudioGenerator::VSVersion
cmLocalVisualStudioGenerator::GetVersion() const
{
cmGlobalVisualStudioGenerator* gg =
static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator);
return gg->GetVersion();
}
2015-04-27 22:25:09 +02:00
void cmLocalVisualStudioGenerator::ComputeObjectFilenames(
2016-07-09 11:21:54 +02:00
std::map<cmSourceFile const*, std::string>& mapping,
cmGeneratorTarget const* gt)
2015-04-27 22:25:09 +02:00
{
2017-07-20 19:35:53 +02:00
char const* custom_ext = gt->GetCustomObjectExtension();
2016-03-13 13:35:51 +01:00
std::string dir_max = this->ComputeLongestObjectDirectory(gt);
2015-04-27 22:25:09 +02:00
// Count the number of object files with each name. Note that
// windows file names are not case sensitive.
std::map<std::string, int> counts;
2018-04-23 21:13:27 +02:00
for (auto const& si : mapping) {
cmSourceFile const* sf = si.first;
2015-04-27 22:25:09 +02:00
std::string objectNameLower = cmSystemTools::LowerCase(
cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath()));
2017-07-20 19:35:53 +02:00
if (custom_ext) {
objectNameLower += custom_ext;
} else {
objectNameLower +=
this->GlobalGenerator->GetLanguageOutputExtension(*sf);
}
2015-04-27 22:25:09 +02:00
counts[objectNameLower] += 1;
2016-07-09 11:21:54 +02:00
}
2015-04-27 22:25:09 +02:00
// For all source files producing duplicate names we need unique
// object name computation.
2018-04-23 21:13:27 +02:00
for (auto& si : mapping) {
cmSourceFile const* sf = si.first;
2015-04-27 22:25:09 +02:00
std::string objectName =
cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath());
2017-07-20 19:35:53 +02:00
if (custom_ext) {
objectName += custom_ext;
} else {
objectName += this->GlobalGenerator->GetLanguageOutputExtension(*sf);
}
2016-07-09 11:21:54 +02:00
if (counts[cmSystemTools::LowerCase(objectName)] > 1) {
2015-04-27 22:25:09 +02:00
const_cast<cmGeneratorTarget*>(gt)->AddExplicitObjectName(sf);
2017-07-20 19:35:53 +02:00
bool keptSourceExtension;
objectName = this->GetObjectFileNameWithoutTarget(
*sf, dir_max, &keptSourceExtension, custom_ext);
2015-04-27 22:25:09 +02:00
}
2018-04-23 21:13:27 +02:00
si.second = objectName;
2016-07-09 11:21:54 +02:00
}
2015-04-27 22:25:09 +02:00
}
2018-01-26 17:06:56 +01:00
std::unique_ptr<cmCustomCommand>
2016-03-13 13:35:51 +01:00
cmLocalVisualStudioGenerator::MaybeCreateImplibDir(cmGeneratorTarget* target,
2015-04-27 22:25:09 +02:00
const std::string& config,
2011-06-19 15:41:06 +03:00
bool isFortran)
2009-10-04 10:30:41 +03:00
{
2018-01-26 17:06:56 +01:00
std::unique_ptr<cmCustomCommand> pcc;
2009-10-04 10:30:41 +03:00
// If an executable exports symbols then VS wants to create an
// import library but forgets to create the output directory.
2011-06-19 15:41:06 +03:00
// The Intel Fortran plugin always forgets to the directory.
2017-04-14 19:02:05 +02:00
if (target->GetType() != cmStateEnums::EXECUTABLE &&
!(isFortran && target->GetType() == cmStateEnums::SHARED_LIBRARY)) {
2016-07-09 11:21:54 +02:00
return pcc;
}
2017-07-20 19:35:53 +02:00
std::string outDir =
target->GetDirectory(config, cmStateEnums::RuntimeBinaryArtifact);
std::string impDir =
target->GetDirectory(config, cmStateEnums::ImportLibraryArtifact);
2016-07-09 11:21:54 +02:00
if (impDir == outDir) {
return pcc;
}
2009-10-04 10:30:41 +03:00
// Add a pre-build event to create the directory.
2020-02-01 23:06:01 +01:00
cmCustomCommandLines commands = cmMakeSingleCommandLine(
{ cmSystemTools::GetCMakeCommand(), "-E", "make_directory", impDir });
2023-05-23 16:38:00 +02:00
pcc = cm::make_unique<cmCustomCommand>();
2022-03-29 21:10:50 +02:00
pcc->SetCommandLines(commands);
pcc->SetStdPipesUTF8(true);
2009-10-04 10:30:41 +03:00
pcc->SetEscapeOldStyle(false);
pcc->SetEscapeAllowMakeVars(true);
return pcc;
}
2011-06-19 15:41:06 +03:00
const char* cmLocalVisualStudioGenerator::ReportErrorLabel() const
2011-01-16 11:35:12 +01:00
{
2011-06-19 15:41:06 +03:00
return ":VCReportError";
2011-01-16 11:35:12 +01:00
}
2011-06-19 15:41:06 +03:00
const char* cmLocalVisualStudioGenerator::GetReportErrorLabel() const
2011-01-16 11:35:12 +01:00
{
2011-06-19 15:41:06 +03:00
return this->ReportErrorLabel();
2011-01-16 11:35:12 +01:00
}
2016-07-09 11:21:54 +02:00
std::string cmLocalVisualStudioGenerator::ConstructScript(
2021-12-08 00:18:10 +01:00
cmCustomCommandGenerator const& ccg, const std::string& newline_text)
{
2011-06-19 15:41:06 +03:00
bool useLocal = this->CustomCommandUseLocal();
2015-04-27 22:25:09 +02:00
std::string workingDirectory = ccg.GetWorkingDirectory();
2011-01-16 11:35:12 +01:00
// Avoid leading or trailing newlines.
2018-01-26 17:06:56 +01:00
std::string newline;
2011-06-19 15:41:06 +03:00
// Line to check for error between commands.
std::string check_error = newline_text;
2016-07-09 11:21:54 +02:00
if (useLocal) {
2011-06-19 15:41:06 +03:00
check_error += "if %errorlevel% neq 0 goto :cmEnd";
2016-07-09 11:21:54 +02:00
} else {
2011-06-19 15:41:06 +03:00
check_error += "if errorlevel 1 goto ";
check_error += this->GetReportErrorLabel();
2016-07-09 11:21:54 +02:00
}
2011-06-19 15:41:06 +03:00
// Store the script in a string.
std::string script;
2011-06-19 15:41:06 +03:00
// Open a local context.
2016-07-09 11:21:54 +02:00
if (useLocal) {
2011-06-19 15:41:06 +03:00
script += newline;
newline = newline_text;
script += "setlocal";
2016-07-09 11:21:54 +02:00
}
2011-06-19 15:41:06 +03:00
2016-07-09 11:21:54 +02:00
if (!workingDirectory.empty()) {
// Change the working directory.
script += newline;
newline = newline_text;
script += "cd ";
2020-08-30 11:54:41 +02:00
script += this->ConvertToOutputFormat(workingDirectory, SHELL);
2011-06-19 15:41:06 +03:00
script += check_error;
// Change the working drive.
2016-07-09 11:21:54 +02:00
if (workingDirectory.size() > 1 && workingDirectory[1] == ':') {
script += newline;
newline = newline_text;
script += workingDirectory[0];
script += workingDirectory[1];
2011-06-19 15:41:06 +03:00
script += check_error;
}
2016-07-09 11:21:54 +02:00
}
2011-06-19 15:41:06 +03:00
// for visual studio IDE add extra stuff to the PATH
// if CMAKE_MSVCIDE_RUN_PATH is set.
2021-11-20 13:41:27 +01:00
if (this->GetGlobalGenerator()->IsVisualStudio()) {
cmValue extraPath =
this->Makefile->GetDefinition("CMAKE_MSVCIDE_RUN_PATH");
2016-07-09 11:21:54 +02:00
if (extraPath) {
script += newline;
newline = newline_text;
script += "set PATH=";
2021-09-14 00:13:48 +02:00
script += *extraPath;
script += ";%PATH%";
}
2016-07-09 11:21:54 +02:00
}
2011-06-19 15:41:06 +03:00
// Write each command on a single line.
2016-07-09 11:21:54 +02:00
for (unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c) {
2018-01-26 17:06:56 +01:00
// Add this command line.
std::string cmd = ccg.GetCommand(c);
if (cmd.empty()) {
continue;
}
// Start a new line.
script += newline;
newline = newline_text;
2012-02-18 12:40:36 +02:00
// Use "call " before any invocations of .bat or .cmd files
// invoked as custom commands.
//
std::string suffix;
2016-07-09 11:21:54 +02:00
if (cmd.size() > 4) {
suffix = cmSystemTools::LowerCase(cmd.substr(cmd.size() - 4));
if (suffix == ".bat" || suffix == ".cmd") {
2012-02-18 12:40:36 +02:00
script += "call ";
}
2016-07-09 11:21:54 +02:00
}
2012-02-18 12:40:36 +02:00
2016-10-30 18:24:19 +01:00
if (workingDirectory.empty()) {
2021-09-14 00:13:48 +02:00
script += this->ConvertToOutputFormat(
this->MaybeRelativeToCurBinDir(cmd), cmOutputConverter::SHELL);
2016-10-30 18:24:19 +01:00
} else {
script += this->ConvertToOutputFormat(cmd.c_str(), SHELL);
}
2011-01-16 11:35:12 +01:00
ccg.AppendArguments(c, script);
2010-06-23 01:18:35 +03:00
// After each custom command, check for an error result.
// If there was an error, jump to the VCReportError label,
// skipping the run of any subsequent commands in this
// sequence.
2011-06-19 15:41:06 +03:00
script += check_error;
2016-07-09 11:21:54 +02:00
}
2011-06-19 15:41:06 +03:00
// Close the local context.
2016-07-09 11:21:54 +02:00
if (useLocal) {
2011-06-19 15:41:06 +03:00
script += newline;
script += ":cmEnd";
script += newline;
script += "endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone";
script += newline;
script += ":cmErrorLevel";
script += newline;
script += "exit /b %1";
script += newline;
script += ":cmDone";
script += newline;
script += "if %errorlevel% neq 0 goto ";
script += this->GetReportErrorLabel();
2016-07-09 11:21:54 +02:00
}
2010-06-23 01:18:35 +03:00
return script;
}
2022-03-29 21:10:50 +02:00
std::string cmLocalVisualStudioGenerator::FinishConstructScript(
VsProjectType projectType, const std::string& newline)
{
bool useLocal = this->CustomCommandUseLocal();
// Store the script in a string.
std::string script;
2022-08-04 22:12:04 +02:00
if (useLocal && projectType != VsProjectType::vcxproj) {
2022-03-29 21:10:50 +02:00
// This label is not provided by MSBuild for C# projects.
script += newline;
script += this->GetReportErrorLabel();
}
return script;
}